diff --git a/ChocolArm64/AThread.cs b/ChocolArm64/AThread.cs
index cec268175f..62f9d2d396 100644
--- a/ChocolArm64/AThread.cs
+++ b/ChocolArm64/AThread.cs
@@ -14,43 +14,30 @@ namespace ChocolArm64
 
         private ATranslator Translator;
 
-        private ThreadPriority Priority;
-
         private Thread Work;
 
         public event EventHandler WorkFinished;
 
         public int ThreadId => ThreadState.ThreadId;
 
-        public bool IsAlive => Work.IsAlive;
+        private int IsExecuting;
 
-        private bool IsExecuting;
-
-        private object ExecuteLock;
-
-        public AThread(ATranslator Translator, AMemory Memory, ThreadPriority Priority, long EntryPoint)
+        public AThread(ATranslator Translator, AMemory Memory, long EntryPoint)
         {
             this.Translator = Translator;
             this.Memory     = Memory;
-            this.Priority   = Priority;
             this.EntryPoint = EntryPoint;
 
             ThreadState = new AThreadState();
-            ExecuteLock = new object();
-        }
 
-        public void StopExecution() => Translator.StopExecution();
+            ThreadState.Running = true;
+        }
 
         public bool Execute()
         {
-            lock (ExecuteLock)
+            if (Interlocked.Exchange(ref IsExecuting, 1) == 1)
             {
-                if (IsExecuting)
-                {
-                    return false;
-                }
-
-                IsExecuting = true;
+                return false;
             }
 
             Work = new Thread(delegate()
@@ -62,11 +49,11 @@ namespace ChocolArm64
                 WorkFinished?.Invoke(this, EventArgs.Empty);
             });
 
-            Work.Priority = Priority;
-
             Work.Start();
 
             return true;
         }
+
+        public void StopExecution() => ThreadState.Running = false;
     }
 }
\ No newline at end of file
diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs
index 1f4a922ab2..02c18efd2b 100644
--- a/ChocolArm64/ATranslator.cs
+++ b/ChocolArm64/ATranslator.cs
@@ -22,8 +22,6 @@ namespace ChocolArm64
 
         public bool EnableCpuTrace { get; set; }
 
-        private bool KeepRunning;
-
         public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
         {
             SubBlocks = new HashSet<long>();
@@ -38,12 +36,8 @@ namespace ChocolArm64
             {
                 this.SymbolTable = new ConcurrentDictionary<long, string>();
             }
-
-            KeepRunning = true;
         }
 
-        internal void StopExecution() => KeepRunning = false;
-
         internal void ExecuteSubroutine(AThread Thread, long Position)
         {
             do
@@ -70,7 +64,7 @@ namespace ChocolArm64
 
                 Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
             }
-            while (Position != 0 && KeepRunning);
+            while (Position != 0 && Thread.ThreadState.Running);
         }
 
         internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
diff --git a/ChocolArm64/Instruction/AInstEmitException.cs b/ChocolArm64/Instruction/AInstEmitException.cs
index fe348edd17..3964c94979 100644
--- a/ChocolArm64/Instruction/AInstEmitException.cs
+++ b/ChocolArm64/Instruction/AInstEmitException.cs
@@ -34,6 +34,22 @@ namespace ChocolArm64.Instruction
 
             Context.EmitCall(MthdInfo);
 
+            //Check if the thread should still be running, if it isn't then we return 0
+            //to force a return to the dispatcher and then exit the thread.
+            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
+
+            Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Running));
+
+            AILLabel LblEnd = new AILLabel();
+
+            Context.Emit(OpCodes.Brtrue_S, LblEnd);
+
+            Context.EmitLdc_I8(0);
+
+            Context.Emit(OpCodes.Ret);
+
+            Context.MarkLabel(LblEnd);
+
             if (Context.CurrBlock.Next != null)
             {
                 Context.EmitLoadState(Context.CurrBlock.Next);
diff --git a/ChocolArm64/State/AThreadState.cs b/ChocolArm64/State/AThreadState.cs
index d86f5bf9c8..ec8621b89b 100644
--- a/ChocolArm64/State/AThreadState.cs
+++ b/ChocolArm64/State/AThreadState.cs
@@ -29,6 +29,8 @@ namespace ChocolArm64.State
         public int ProcessId;
         public int ThreadId;
 
+        public bool Running { get; set; }
+
         public long TpidrEl0 { get; set; }
         public long Tpidr    { get; set; }
 
diff --git a/Ryujinx.Core/Hid/Hid.cs b/Ryujinx.Core/Hid/Hid.cs
index c287564d3a..f25a943752 100644
--- a/Ryujinx.Core/Hid/Hid.cs
+++ b/Ryujinx.Core/Hid/Hid.cs
@@ -63,17 +63,13 @@ namespace Ryujinx.Core.Input
 
         private object ShMemLock;
 
-        private long[] ShMemPositions;
+        private (AMemory, long)[] ShMemPositions;
 
-        private AMemory Memory;
-
-        public Hid(AMemory Memory)
+        public Hid()
         {
-            this.Memory = Memory;
-
             ShMemLock = new object();
 
-            ShMemPositions = new long[0];
+            ShMemPositions = new (AMemory, long)[0];
         }
 
         internal void ShMemMap(object sender, EventArgs e)
@@ -84,11 +80,11 @@ namespace Ryujinx.Core.Input
             {
                 ShMemPositions = SharedMem.GetVirtualPositions();
 
-                long BasePosition = ShMemPositions[ShMemPositions.Length - 1];
+                (AMemory Memory, long Position) ShMem = ShMemPositions[ShMemPositions.Length - 1];
 
-                Logging.Info($"HID shared memory successfully mapped to 0x{BasePosition:x16}!");
+                Logging.Info($"HID shared memory successfully mapped to 0x{ShMem.Position:x16}!");
 
-                Init(BasePosition);
+                Init(ShMem.Memory, ShMem.Position);
             }
         }
 
@@ -102,10 +98,11 @@ namespace Ryujinx.Core.Input
             }
         }
 
-        private void Init(long BasePosition)
+        private void Init(AMemory Memory, long Position)
         {
             InitializeJoyconPair(
-                BasePosition,
+                Memory,
+                Position,
                 JoyConColor.Body_Neon_Red,
                 JoyConColor.Buttons_Neon_Red,
                 JoyConColor.Body_Neon_Blue,
@@ -113,13 +110,14 @@ namespace Ryujinx.Core.Input
         }
 
         private void InitializeJoyconPair(
-            long        BasePosition,
+            AMemory     Memory,
+            long        Position,
             JoyConColor LeftColorBody,
             JoyConColor LeftColorButtons,
             JoyConColor RightColorBody,
             JoyConColor RightColorButtons)
         {
-            long BaseControllerOffset = BasePosition + HidControllersOffset + 8 * HidControllerSize;
+            long BaseControllerOffset = Position + HidControllersOffset + 8 * HidControllerSize;
 
             HidControllerType Type =
                 HidControllerType.ControllerType_Handheld |
@@ -160,7 +158,7 @@ namespace Ryujinx.Core.Input
         {
             lock (ShMemLock)
             {
-                foreach (long Position in ShMemPositions)
+                foreach ((AMemory Memory, long Position) in ShMemPositions)
                 {
                     long ControllerOffset = Position + HidControllersOffset;
 
@@ -207,7 +205,7 @@ namespace Ryujinx.Core.Input
         {
             lock (ShMemLock)
             {
-                foreach (long Position in ShMemPositions)
+                foreach ((AMemory Memory, long Position) in ShMemPositions)
                 {
                     long TouchScreenOffset = Position + HidTouchScreenOffset;
 
diff --git a/Ryujinx.Core/Logging.cs b/Ryujinx.Core/Logging.cs
index d544a5d64f..89064ccbc8 100644
--- a/Ryujinx.Core/Logging.cs
+++ b/Ryujinx.Core/Logging.cs
@@ -8,7 +8,8 @@ namespace Ryujinx.Core
 {
     public static class Logging
     {
-        private static Stopwatch ExecutionTime = new Stopwatch();
+        private static Stopwatch ExecutionTime;
+
         private const string LogFileName = "Ryujinx.log";
 
         private static bool EnableInfo    = Config.LoggingEnableInfo;
@@ -23,6 +24,10 @@ namespace Ryujinx.Core
         static Logging()
         {
             if (File.Exists(LogFileName)) File.Delete(LogFileName);
+
+            ExecutionTime = new Stopwatch();
+
+            ExecutionTime.Start();
         }
 
         public static string GetExecutionTime()
diff --git a/Ryujinx.Core/OsHle/CondVar.cs b/Ryujinx.Core/OsHle/CondVar.cs
index ac3ba57498..f5fe3d292e 100644
--- a/Ryujinx.Core/OsHle/CondVar.cs
+++ b/Ryujinx.Core/OsHle/CondVar.cs
@@ -4,7 +4,7 @@ using System.Threading;
 
 namespace Ryujinx.Core.OsHle
 {
-    public class CondVar
+    class CondVar
     {
         private Process Process;
 
diff --git a/Ryujinx.Core/OsHle/Handles/HDomain.cs b/Ryujinx.Core/OsHle/Handles/HDomain.cs
index ca287a5fda..ac99b03a6b 100644
--- a/Ryujinx.Core/OsHle/Handles/HDomain.cs
+++ b/Ryujinx.Core/OsHle/Handles/HDomain.cs
@@ -1,58 +1,48 @@
-using Ryujinx.Core.OsHle.Utilities;
 using System;
-using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.Handles
 {
-    class HDomain : HSession
+    class HDomain : HSession, IDisposable
     {
-        private Dictionary<int, object> Objects;
-
-        private IdPool ObjIds;
+        private IdDictionary Objects;
 
         public HDomain(HSession Session) : base(Session)
         {
-            Objects = new Dictionary<int, object>();
-
-            ObjIds = new IdPool();
+            Objects = new IdDictionary();
         }
 
-        public int GenerateObjectId(object Obj)
+        public int Add(object Obj)
         {
-            int Id = ObjIds.GenerateId();
-
-            if (Id == -1)
-            {
-                throw new InvalidOperationException();
-            }
-
-            Objects.Add(Id, Obj);
-
-            return Id;
+            return Objects.Add(Obj);
         }
 
-        public void DeleteObject(int Id)
+        public bool Delete(int Id)
         {
-            if (Objects.TryGetValue(Id, out object Obj))
-            {
-                if (Obj is IDisposable DisposableObj)
-                {
-                    DisposableObj.Dispose();
-                }
-
-                ObjIds.DeleteId(Id);
-                Objects.Remove(Id);
-            }
+            return Objects.Delete(Id);
         }
 
         public object GetObject(int Id)
         {
-            if (Objects.TryGetValue(Id, out object Obj))
-            {
-                return Obj;
-            }
+            return Objects.GetData(Id);
+        }
 
-            return null;
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                foreach (object Obj in Objects)
+                {
+                    if (Obj is IDisposable DisposableObj)
+                    {
+                        DisposableObj.Dispose();
+                    }
+                }
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HNvMap.cs b/Ryujinx.Core/OsHle/Handles/HNvMap.cs
deleted file mode 100644
index 09173730b3..0000000000
--- a/Ryujinx.Core/OsHle/Handles/HNvMap.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Ryujinx.Core.OsHle.Handles
-{
-    class HNvMap
-    {
-        public int Id    { get; private set; }
-        public int Size  { get; private set; }
-
-        public int  Align   { get; set; }
-        public int  Kind    { get; set; }
-        public long Address { get; set; }
-        
-        public HNvMap(int Id, int Size)
-        {
-            this.Id   = Id;
-            this.Size = Size;
-        }
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs
index eb173e9652..b6bdc89878 100644
--- a/Ryujinx.Core/OsHle/Handles/HSharedMem.cs
+++ b/Ryujinx.Core/OsHle/Handles/HSharedMem.cs
@@ -1,3 +1,4 @@
+using ChocolArm64.Memory;
 using System;
 using System.Collections.Generic;
 
@@ -5,37 +6,37 @@ namespace Ryujinx.Core.OsHle.Handles
 {
     class HSharedMem
     {
-        private List<long> Positions;
+        private List<(AMemory, long)> Positions;
 
         public EventHandler<EventArgs> MemoryMapped;
         public EventHandler<EventArgs> MemoryUnmapped;
 
         public HSharedMem()
         {
-            Positions = new List<long>();
+            Positions = new List<(AMemory, long)>();
         }
 
-        public void AddVirtualPosition(long Position)
+        public void AddVirtualPosition(AMemory Memory, long Position)
         {
             lock (Positions)
             {
-                Positions.Add(Position);
+                Positions.Add((Memory, Position));
 
                 MemoryMapped?.Invoke(this, EventArgs.Empty);
             }
         }
 
-        public void RemoveVirtualPosition(long Position)
+        public void RemoveVirtualPosition(AMemory Memory, long Position)
         {
             lock (Positions)
             {
-                Positions.Remove(Position);
+                Positions.Remove((Memory, Position));
 
                 MemoryUnmapped?.Invoke(this, EventArgs.Empty);
             }
         }
 
-        public long[] GetVirtualPositions()
+        public (AMemory, long)[] GetVirtualPositions()
         {
             return Positions.ToArray();
         }
diff --git a/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs b/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs
new file mode 100644
index 0000000000..1156e035fd
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Handles/KProcessHandleTable.cs
@@ -0,0 +1,63 @@
+using System;
+
+namespace Ryujinx.Core.OsHle.Handles
+{
+    class KProcessHandleTable : IDisposable
+    {
+        private IdDictionary Handles;
+
+        public KProcessHandleTable()
+        {
+            Handles = new IdDictionary();
+        }
+
+        public int OpenHandle(object Obj)
+        {
+            return Handles.Add(Obj);
+        }
+
+        public T GetData<T>(int Handle)
+        {
+            return Handles.GetData<T>(Handle);
+        }
+
+        public bool ReplaceData(int Id, object Data)
+        {
+            return Handles.ReplaceData(Id, Data);
+        }
+
+        public bool CloseHandle(int Handle)
+        {
+            object Data = Handles.GetData(Handle);
+
+            if (Data is HTransferMem TMem)
+            {
+                TMem.Memory.Manager.Reprotect(
+                    TMem.Position,
+                    TMem.Size,
+                    TMem.Perm);
+            }
+
+            return Handles.Delete(Handle);
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                foreach (object Obj in Handles)
+                {
+                    if (Obj is IDisposable DisposableObj)
+                    {
+                        DisposableObj.Dispose();
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Homebrew.cs b/Ryujinx.Core/OsHle/Homebrew.cs
index e2e95e4d41..2a717ca738 100644
--- a/Ryujinx.Core/OsHle/Homebrew.cs
+++ b/Ryujinx.Core/OsHle/Homebrew.cs
@@ -37,5 +37,33 @@ namespace Ryujinx.Core.OsHle
 
             Position += 0x18;
         }
+
+        public static string ReadHbAbiNextLoadPath(AMemory Memory, long Position)
+        {
+            string FileName = null;
+
+            while (true)
+            {
+                long Key = Memory.ReadInt64(Position);
+
+                if (Key == 2)
+                {
+                    long Value0 = Memory.ReadInt64(Position + 0x08);
+                    long Value1 = Memory.ReadInt64(Position + 0x10);
+
+                    FileName = AMemoryHelper.ReadAsciiString(Memory, Value0, (int)(Value1 - Value0));
+
+                    break;
+                }
+                else if (Key == 0)
+                {
+                    break;
+                }
+
+                Position += 0x18;
+            }
+
+            return FileName;
+        }
     }
 }
diff --git a/Ryujinx.Core/OsHle/Horizon.cs b/Ryujinx.Core/OsHle/Horizon.cs
index c61e18e98f..c3f8cd8b00 100644
--- a/Ryujinx.Core/OsHle/Horizon.cs
+++ b/Ryujinx.Core/OsHle/Horizon.cs
@@ -1,33 +1,23 @@
 using Ryujinx.Core.Loaders.Executables;
 using Ryujinx.Core.OsHle.Handles;
-using Ryujinx.Core.OsHle.Utilities;
 using System;
 using System.Collections.Concurrent;
 using System.IO;
 
 namespace Ryujinx.Core.OsHle
 {
-    public class Horizon
+    public class Horizon : IDisposable
     {
         internal const int HidSize  = 0x40000;
         internal const int FontSize = 0x50;
 
-        internal int HidHandle  { get; private set; }
-        internal int FontHandle { get; private set; }
-
-        internal IdPool IdGen    { get; private set; }
-        internal IdPool NvMapIds { get; private set; }
-
-        internal IdPoolWithObj Handles  { get; private set; }
-        internal IdPoolWithObj Fds      { get; private set; }
-        internal IdPoolWithObj Displays { get; private set; }
-
-        public ConcurrentDictionary<long, Mutex>   Mutexes  { get; private set; }
-        public ConcurrentDictionary<long, CondVar> CondVars { get; private set; }
+        internal ConcurrentDictionary<long, Mutex>   Mutexes  { get; private set; }
+        internal ConcurrentDictionary<long, CondVar> CondVars { get; private set; }
 
         private ConcurrentDictionary<int, Process> Processes;
 
         internal HSharedMem HidSharedMem;
+        internal HSharedMem FontSharedMem;
 
         private Switch Ns;
 
@@ -35,25 +25,13 @@ namespace Ryujinx.Core.OsHle
         {
             this.Ns = Ns;
 
-            IdGen    = new IdPool();
-            NvMapIds = new IdPool();
-
-            Handles  = new IdPoolWithObj();
-            Fds      = new IdPoolWithObj();
-            Displays = new IdPoolWithObj();
-
             Mutexes  = new ConcurrentDictionary<long, Mutex>();
             CondVars = new ConcurrentDictionary<long, CondVar>();
 
             Processes = new ConcurrentDictionary<int, Process>();
 
-            HidSharedMem = new HSharedMem();
-
-            HidHandle = Handles.GenerateId(HidSharedMem);
-
-            FontHandle = Handles.GenerateId(new HSharedMem());
-
-            HidSharedMem.AddVirtualPosition(0);
+            HidSharedMem  = new HSharedMem();
+            FontSharedMem = new HSharedMem();
         }
 
         public void LoadCart(string ExeFsDir, string RomFsFile = null)
@@ -63,9 +41,7 @@ namespace Ryujinx.Core.OsHle
                 Ns.VFs.LoadRomFs(RomFsFile);
             }
 
-            int ProcessId = IdGen.GenerateId();
-
-            Process MainProcess = new Process(Ns, ProcessId);
+            Process MainProcess = MakeProcess();
 
             void LoadNso(string FileName)
             {
@@ -96,17 +72,13 @@ namespace Ryujinx.Core.OsHle
             LoadNso("sdk");
 
             MainProcess.Run();
-
-            Processes.TryAdd(ProcessId, MainProcess);
         }
 
         public void LoadProgram(string FileName)
         {
             bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro";
 
-            int ProcessId = IdGen.GenerateId();
-
-            Process MainProcess = new Process(Ns, ProcessId);
+            Process MainProcess = MakeProcess();
 
             using (FileStream Input = new FileStream(FileName, FileMode.Open))
             {
@@ -117,34 +89,67 @@ namespace Ryujinx.Core.OsHle
 
             MainProcess.SetEmptyArgs();
             MainProcess.Run(IsNro);
-
-            Processes.TryAdd(ProcessId, MainProcess);
         }
 
-        public void FinalizeAllProcesses()
+        private Process MakeProcess()
         {
-            foreach (Process Process in Processes.Values)
+            Process Process;
+
+            lock (Processes)
             {
-                Process.StopAllThreads();
+                int ProcessId = 0;
+
+                while (Processes.ContainsKey(ProcessId))
+                {
+                    ProcessId++;
+                }
+
+                Process = new Process(Ns, ProcessId);
+
+                Processes.TryAdd(ProcessId, Process);
+            }
+
+            return Process;
+        }
+
+        internal void ExitProcess(int ProcessId)
+        {
+            if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
+            {
+                string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition);
+
+                Logging.Info($"HbAbi NextLoadPath {NextNro}");
+
+                if (NextNro == string.Empty)
+                {
+                    NextNro = "sdmc:/hbmenu.nro";
+                }
+
+                NextNro = NextNro.Replace("sdmc:", string.Empty);
+
+                NextNro = Ns.VFs.GetFullPath(Ns.VFs.GetSdCardPath(), NextNro);
+
+                if (File.Exists(NextNro))
+                {
+                    //TODO: Those dictionaries shouldn't even exist,
+                    //the Mutex and CondVar helper classes should be static.
+                    Mutexes.Clear();
+                    CondVars.Clear();
+
+                    LoadProgram(NextNro);
+                }
+            }
+
+            if (Processes.TryRemove(ProcessId, out Process))
+            {
+                Process.StopAllThreadsAsync();
                 Process.Dispose();
-            }
-        }
 
-        internal bool ExitProcess(int ProcessId)
-        {
-            bool Success = Processes.TryRemove(ProcessId, out Process Process);
-            
-            if (Success)
-            {
-                Process.StopAllThreads();
+                if (Processes.Count == 0)
+                {
+                    Ns.OnFinish(EventArgs.Empty);
+                }
             }
-
-            if (Processes.Count == 0)
-            {
-                Ns.OnFinish(EventArgs.Empty);
-            }
-
-            return Success;
         }
 
         internal bool TryGetProcess(int ProcessId, out Process Process)
@@ -152,19 +157,21 @@ namespace Ryujinx.Core.OsHle
             return Processes.TryGetValue(ProcessId, out Process);
         }
 
-        internal void CloseHandle(int Handle)
+        public void Dispose()
         {
-            object HndData = Handles.GetData<object>(Handle);
+            Dispose(true);
+        }
 
-            if (HndData is HTransferMem TransferMem)
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
             {
-                TransferMem.Memory.Manager.Reprotect(
-                    TransferMem.Position,
-                    TransferMem.Size,
-                    TransferMem.Perm);
+                foreach (Process Process in Processes.Values)
+                {
+                    Process.StopAllThreadsAsync();
+                    Process.Dispose();
+                }
             }
-
-            Handles.Delete(Handle);
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs b/Ryujinx.Core/OsHle/IdDictionary.cs
similarity index 50%
rename from Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs
rename to Ryujinx.Core/OsHle/IdDictionary.cs
index f0a339df3a..0b90924616 100644
--- a/Ryujinx.Core/OsHle/Utilities/IdPoolWithObj.cs
+++ b/Ryujinx.Core/OsHle/IdDictionary.cs
@@ -3,31 +3,40 @@ using System.Collections;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 
-namespace Ryujinx.Core.OsHle.Utilities
+namespace Ryujinx.Core.OsHle
 {
-    class IdPoolWithObj : IEnumerable<KeyValuePair<int, object>>
+    class IdDictionary : IEnumerable<object>
     {
-        private IdPool Ids;
-
         private ConcurrentDictionary<int, object> Objs;
 
-        public IdPoolWithObj()
-        {
-            Ids = new IdPool();
+        private int FreeIdHint = 1;
 
+        public IdDictionary()
+        {
             Objs = new ConcurrentDictionary<int, object>();
         }
 
-        public int GenerateId(object Data)
+        public int Add(object Data)
         {
-            int Id = Ids.GenerateId();
-
-            if (Id == -1 || !Objs.TryAdd(Id, Data))
+            if (Objs.TryAdd(FreeIdHint, Data))
             {
-                throw new InvalidOperationException();
+                return FreeIdHint++;
             }
 
-            return Id;
+            return AddSlow(Data);
+        }
+
+        private int AddSlow(object Data)
+        {
+            for (int Id = 1; Id < int.MaxValue; Id++)
+            {
+                if (Objs.TryAdd(Id, Data))
+                {
+                    return Id;
+                }
+            }
+
+            throw new InvalidOperationException();
         }
 
         public bool ReplaceData(int Id, object Data)
@@ -42,6 +51,16 @@ namespace Ryujinx.Core.OsHle.Utilities
             return false;
         }
 
+        public object GetData(int Id)
+        {
+            if (Objs.TryGetValue(Id, out object Data))
+            {
+                return Data;
+            }
+
+            return null;
+        }
+
         public T GetData<T>(int Id)
         {
             if (Objs.TryGetValue(Id, out object Data) && Data is T)
@@ -52,7 +71,7 @@ namespace Ryujinx.Core.OsHle.Utilities
             return default(T);
         }
 
-        public void Delete(int Id)
+        public bool Delete(int Id)
         {
             if (Objs.TryRemove(Id, out object Obj))
             {
@@ -61,18 +80,22 @@ namespace Ryujinx.Core.OsHle.Utilities
                     DisposableObj.Dispose();
                 }
 
-                Ids.DeleteId(Id);
+                FreeIdHint = Id;
+
+                return true;
             }
+
+            return false;
         }
 
-        IEnumerator<KeyValuePair<int, object>> IEnumerable<KeyValuePair<int, object>>.GetEnumerator()
+        IEnumerator<object> IEnumerable<object>.GetEnumerator()
         {
-            return Objs.GetEnumerator();
+            return Objs.Values.GetEnumerator();
         }
 
         IEnumerator IEnumerable.GetEnumerator()
         {
-            return Objs.GetEnumerator();
+            return Objs.Values.GetEnumerator();
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
index 2495d7014c..f2179a962c 100644
--- a/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
+++ b/Ryujinx.Core/OsHle/Ipc/IpcHandler.cs
@@ -13,6 +13,7 @@ namespace Ryujinx.Core.OsHle.Ipc
 
         public static void IpcCall(
             Switch     Ns,
+            Process    Process,
             AMemory    Memory,
             HSession   Session,
             IpcMessage Request,
@@ -60,7 +61,7 @@ namespace Ryujinx.Core.OsHle.Ipc
                         }
                         else if (Request.DomCmd == IpcDomCmd.DeleteObj)
                         {
-                            Dom.DeleteObject(Request.DomObjId);
+                            Dom.Delete(Request.DomObjId);
 
                             Response = FillResponse(Response, 0);
 
@@ -100,6 +101,7 @@ namespace Ryujinx.Core.OsHle.Ipc
 
                             ServiceCtx Context = new ServiceCtx(
                                 Ns,
+                                Process,
                                 Memory,
                                 Session,
                                 Request,
@@ -124,15 +126,43 @@ namespace Ryujinx.Core.OsHle.Ipc
 
                     switch (CmdId)
                     {
-                        case 0: Request = IpcConvertSessionToDomain(Ns, Session, Response, HndId); break;
-                        case 3: Request = IpcQueryBufferPointerSize(Response);                     break;
-                        case 2: //IpcDuplicateSession, differences is unknown. 
-                        case 4: Request = IpcDuplicateSessionEx(Ns, Session, Response, ReqReader); break;
+                        case 0:
+                        {
+                            HDomain Dom = new HDomain(Session);
+
+                            Process.HandleTable.ReplaceData(HndId, Dom);
+
+                            Request = FillResponse(Response, 0, Dom.Add(Dom));
+
+                            break;
+                        }
+
+                        case 3:
+                        {
+                            Request = FillResponse(Response, 0, 0x500);
+                            
+                            break;
+                        }
+
+                        //TODO: Whats the difference between IpcDuplicateSession/Ex? 
+                        case 2: 
+                        case 4:
+                        {
+                            int Unknown = ReqReader.ReadInt32();
+
+                            int Handle = Process.HandleTable.OpenHandle(Session);
+
+                            Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
+
+                            Request = FillResponse(Response, 0);
+
+                            break;
+                        }
 
                         default: throw new NotImplementedException(CmdId.ToString());
                     }
                 }
-                else if (Request.Type == IpcMessageType.Unknown2)
+                else if (Request.Type == IpcMessageType.CloseSession)
                 {
                     //TODO
                 }
@@ -145,39 +175,6 @@ namespace Ryujinx.Core.OsHle.Ipc
             }
         }
 
-        private static IpcMessage IpcConvertSessionToDomain(
-            Switch     Ns,
-            HSession   Session,
-            IpcMessage Response,
-            int        HndId)
-        {
-            HDomain Dom = new HDomain(Session);
-
-            Ns.Os.Handles.ReplaceData(HndId, Dom);
-
-            return FillResponse(Response, 0, Dom.GenerateObjectId(Dom));
-        }
-
-        private static IpcMessage IpcDuplicateSessionEx(
-            Switch       Ns,
-            HSession     Session,
-            IpcMessage   Response,
-            BinaryReader ReqReader)
-        {
-            int Unknown = ReqReader.ReadInt32();
-
-            int Handle = Ns.Os.Handles.GenerateId(Session);
-
-            Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
-
-            return FillResponse(Response, 0);
-        }
-
-        private static IpcMessage IpcQueryBufferPointerSize(IpcMessage Response)
-        {
-            return FillResponse(Response, 0, 0x500);
-        }
-
         private static IpcMessage FillResponse(IpcMessage Response, long Result, params int[] Values)
         {
             using (MemoryStream MS = new MemoryStream())
diff --git a/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs
index 8027508de2..560af41e74 100644
--- a/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs
+++ b/Ryujinx.Core/OsHle/Ipc/IpcMessageType.cs
@@ -2,9 +2,9 @@ namespace Ryujinx.Core.OsHle.Ipc
 {
     enum IpcMessageType
     {
-        Response = 0,
-        Unknown2 = 2,
-        Request  = 4,
-        Control  = 5
+        Response     = 0,
+        CloseSession = 2,
+        Request      = 4,
+        Control      = 5
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Mutex.cs b/Ryujinx.Core/OsHle/Mutex.cs
index c95ed77164..c619e12174 100644
--- a/Ryujinx.Core/OsHle/Mutex.cs
+++ b/Ryujinx.Core/OsHle/Mutex.cs
@@ -4,7 +4,7 @@ using System.Threading;
 
 namespace Ryujinx.Core.OsHle
 {
-    public class Mutex
+    class Mutex
     {
         private const int MutexHasListenersMask = 0x40000000;
 
diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs
index a919f1af6d..a8719e1c29 100644
--- a/Ryujinx.Core/OsHle/Process.cs
+++ b/Ryujinx.Core/OsHle/Process.cs
@@ -9,25 +9,32 @@ using Ryujinx.Core.OsHle.Svc;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
-using System.Threading;
 
 namespace Ryujinx.Core.OsHle
 {
-    public class Process : IDisposable
+    class Process : IDisposable
     {
-        private const int  TlsSize       = 0x200;
-        private const int  TotalTlsSlots = 32;
+        private const int TlsSize       = 0x200;
+        private const int TotalTlsSlots = 32;
 
         private Switch Ns;
 
+        public bool NeedsHbAbi { get; private set; }
+
+        public long HbAbiDataPosition { get; private set; }
+
         public int ProcessId { get; private set; }
 
         private ATranslator Translator;
 
         public AMemory Memory { get; private set; }
 
+        public ServiceMgr Services { get; private set; }
+
         public KProcessScheduler Scheduler { get; private set; }
 
+        public KProcessHandleTable HandleTable { get; private set; }
+
         private SvcHandler SvcHandler;
 
         private ConcurrentDictionary<int, AThread> TlsSlots;
@@ -40,14 +47,22 @@ namespace Ryujinx.Core.OsHle
 
         private long ImageBase;
 
+        private bool ShouldDispose;
+
+        private bool Disposed;
+
         public Process(Switch Ns, int ProcessId)
         {
             this.Ns        = Ns;
             this.ProcessId = ProcessId;
 
-            Memory = Ns.Memory;
+            Memory = new AMemory();
 
-            Scheduler = new KProcessScheduler();
+            Services = new ServiceMgr();
+
+            HandleTable = new KProcessHandleTable();
+
+            Scheduler = new KProcessScheduler();            
 
             SvcHandler = new SvcHandler(Ns, this);
 
@@ -67,6 +82,11 @@ namespace Ryujinx.Core.OsHle
 
         public void LoadProgram(IExecutable Program)
         {
+            if (Disposed)
+            {
+                throw new ObjectDisposedException(nameof(Process));
+            }
+
             Logging.Info($"Image base at 0x{ImageBase:x16}.");
 
             Executable Executable = new Executable(Program, Memory, ImageBase);
@@ -78,11 +98,19 @@ namespace Ryujinx.Core.OsHle
 
         public void SetEmptyArgs()
         {
+            //TODO: This should be part of Run.
             ImageBase += AMemoryMgr.PageSize;
         }
 
-        public bool Run(bool UseHbAbi = false)
+        public bool Run(bool NeedsHbAbi = false)
         {
+            if (Disposed)
+            {
+                throw new ObjectDisposedException(nameof(Process));
+            }
+
+            this.NeedsHbAbi = NeedsHbAbi;
+
             if (Executables.Count == 0)
             {
                 return false;
@@ -102,11 +130,11 @@ namespace Ryujinx.Core.OsHle
                 return false;
             }
 
-            MainThread = Ns.Os.Handles.GetData<HThread>(Handle);
+            MainThread = HandleTable.GetData<HThread>(Handle);
 
-            if (UseHbAbi)
+            if (NeedsHbAbi)
             {
-                long HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd);
+                HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd);
 
                 Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle);
 
@@ -124,22 +152,21 @@ namespace Ryujinx.Core.OsHle
             Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
         }
 
-        public void StopAllThreads()
+        public void StopAllThreadsAsync()
         {
+            if (Disposed)
+            {
+                throw new ObjectDisposedException(nameof(Process));
+            }
+
             if (MainThread != null)
             {
-                while (MainThread.Thread.IsAlive)
-                {
-                    MainThread.Thread.StopExecution();
-                }
+                MainThread.Thread.StopExecution();
             }
 
             foreach (AThread Thread in TlsSlots.Values)
             {
-                while (Thread.IsAlive)
-                {
-                    Thread.StopExecution();
-                }
+                Thread.StopExecution();
             }
         }
 
@@ -150,49 +177,26 @@ namespace Ryujinx.Core.OsHle
             int  Priority,
             int  ProcessorId)
         {
-            ThreadPriority ThreadPrio;
-
-            if (Priority < 12)
+            if (Disposed)
             {
-                ThreadPrio = ThreadPriority.Highest;
-            }
-            else if (Priority < 24)
-            {
-                ThreadPrio = ThreadPriority.AboveNormal;
-            }
-            else if (Priority < 36)
-            {
-                ThreadPrio = ThreadPriority.Normal;
-            }
-            else if (Priority < 48)
-            {
-                ThreadPrio = ThreadPriority.BelowNormal;
-            }
-            else
-            {
-                ThreadPrio = ThreadPriority.Lowest;
+                throw new ObjectDisposedException(nameof(Process));
             }
 
-            AThread Thread = new AThread(GetTranslator(), Memory, ThreadPrio, EntryPoint);
+            AThread Thread = new AThread(GetTranslator(), Memory, EntryPoint);
 
             HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
 
-            int Handle = Ns.Os.Handles.GenerateId(ThreadHnd);
+            int Handle = HandleTable.OpenHandle(ThreadHnd);
 
-            int TlsSlot = GetFreeTlsSlot(Thread);
+            int ThreadId = GetFreeTlsSlot(Thread);
 
-            if (TlsSlot == -1 || Handle  == -1)
-            {
-                return -1;
-            }
-
-            long Tpidr = MemoryRegions.TlsPagesAddress + TlsSlot * TlsSize;
+            long Tpidr = MemoryRegions.TlsPagesAddress + ThreadId * TlsSize;
 
             Thread.ThreadState.Break     += BreakHandler;
             Thread.ThreadState.SvcCall   += SvcHandler.SvcCall;
             Thread.ThreadState.Undefined += UndefinedHandler;
             Thread.ThreadState.ProcessId  = ProcessId;
-            Thread.ThreadState.ThreadId   = Ns.Os.IdGen.GenerateId();
+            Thread.ThreadState.ThreadId   = ThreadId;
             Thread.ThreadState.Tpidr      = Tpidr;
             Thread.ThreadState.X0         = (ulong)ArgsPtr;
             Thread.ThreadState.X1         = (ulong)Handle;
@@ -224,7 +228,7 @@ namespace Ryujinx.Core.OsHle
                 foreach (Executable Exe in Executables)
                 {
                     foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
-                    {                        
+                    {
                         SymbolTable.TryAdd(Exe.ImageBase + KV.Key, KV.Value);
                     }
                 }
@@ -274,16 +278,28 @@ namespace Ryujinx.Core.OsHle
                 }
             }
 
-            return -1;
+            throw new InvalidOperationException();
         }
 
         private void ThreadFinished(object sender, EventArgs e)
         {
             if (sender is AThread Thread)
             {
-                TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _);
+                Logging.Info($"Thread {Thread.ThreadId} exiting...");
 
-                Ns.Os.IdGen.DeleteId(Thread.ThreadId);
+                TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _);
+            }
+
+            if (TlsSlots.Count == 0)
+            {
+                if (ShouldDispose)
+                {
+                    Dispose();
+                }
+
+                Logging.Info($"No threads running, now exiting Process {ProcessId}...");
+
+                Ns.Os.ExitProcess(ProcessId);
             }
         }
 
@@ -309,9 +325,30 @@ namespace Ryujinx.Core.OsHle
 
         protected virtual void Dispose(bool Disposing)
         {
-            if (Disposing)
+            if (Disposing && !Disposed)
             {
+                //If there is still some thread running, disposing the objects is not
+                //safe as the thread may try to access those resources. Instead, we set
+                //the flag to have the Process disposed when all threads finishes.
+                //Note: This may not happen if the guest code gets stuck on a infinite loop.
+                if (TlsSlots.Count > 0)
+                {
+                    ShouldDispose = true;
+
+                    Logging.Info($"Process {ProcessId} waiting all threads terminate...");
+
+                    return;
+                }
+
+                Disposed = true;
+                
+                Services.Dispose();
+                HandleTable.Dispose();
                 Scheduler.Dispose();
+                SvcHandler.Dispose();
+                Memory.Dispose();
+
+                Logging.Info($"Process {ProcessId} exiting...");
             }
         }
     }
diff --git a/Ryujinx.Core/OsHle/ServiceCtx.cs b/Ryujinx.Core/OsHle/ServiceCtx.cs
index 31ecce3dec..60c378d5a7 100644
--- a/Ryujinx.Core/OsHle/ServiceCtx.cs
+++ b/Ryujinx.Core/OsHle/ServiceCtx.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.Core.OsHle
     class ServiceCtx
     {
         public Switch       Ns           { get; private set; }
+        public Process      Process      { get; private set; }
         public AMemory      Memory       { get; private set; }
         public HSession     Session      { get; private set; }
         public IpcMessage   Request      { get; private set; }
@@ -17,6 +18,7 @@ namespace Ryujinx.Core.OsHle
 
         public ServiceCtx(
             Switch       Ns,
+            Process      Process,
             AMemory      Memory,
             HSession     Session,
             IpcMessage   Request,
@@ -25,6 +27,7 @@ namespace Ryujinx.Core.OsHle
             BinaryWriter ResponseData)
         {
             this.Ns           = Ns;
+            this.Process      = Process;
             this.Memory       = Memory;
             this.Session      = Session;
             this.Request      = Request;
diff --git a/Ryujinx.Core/OsHle/ServiceMgr.cs b/Ryujinx.Core/OsHle/ServiceMgr.cs
new file mode 100644
index 0000000000..cbf6386f9d
--- /dev/null
+++ b/Ryujinx.Core/OsHle/ServiceMgr.cs
@@ -0,0 +1,109 @@
+using Ryujinx.Core.OsHle.IpcServices;
+using Ryujinx.Core.OsHle.IpcServices.Acc;
+using Ryujinx.Core.OsHle.IpcServices.Am;
+using Ryujinx.Core.OsHle.IpcServices.Apm;
+using Ryujinx.Core.OsHle.IpcServices.Aud;
+using Ryujinx.Core.OsHle.IpcServices.Bsd;
+using Ryujinx.Core.OsHle.IpcServices.Friend;
+using Ryujinx.Core.OsHle.IpcServices.FspSrv;
+using Ryujinx.Core.OsHle.IpcServices.Hid;
+using Ryujinx.Core.OsHle.IpcServices.Lm;
+using Ryujinx.Core.OsHle.IpcServices.Nifm;
+using Ryujinx.Core.OsHle.IpcServices.Ns;
+using Ryujinx.Core.OsHle.IpcServices.NvServices;
+using Ryujinx.Core.OsHle.IpcServices.Pctl;
+using Ryujinx.Core.OsHle.IpcServices.Pl;
+using Ryujinx.Core.OsHle.IpcServices.Set;
+using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
+using Ryujinx.Core.OsHle.IpcServices.Sm;
+using Ryujinx.Core.OsHle.IpcServices.Ssl;
+using Ryujinx.Core.OsHle.IpcServices.Time;
+using Ryujinx.Core.OsHle.IpcServices.Vi;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Core.OsHle
+{
+    class ServiceMgr : IDisposable
+    {
+        private Dictionary<string, IIpcService> Services;
+
+        public ServiceMgr()
+        {
+            Services = new Dictionary<string, IIpcService>();
+        }
+
+        public IIpcService GetService(string Name)
+        {
+            lock (Services)
+            {
+                if (!Services.TryGetValue(Name, out IIpcService Service))
+                {
+                    switch (Name)
+                    {
+                        case "acc:u0":   Service = new ServiceAcc();      break;
+                        case "aoc:u":    Service = new ServiceNs();       break;
+                        case "apm":      Service = new ServiceApm();      break;
+                        case "apm:p":    Service = new ServiceApm();      break;
+                        case "appletOE": Service = new ServiceAppletOE(); break;
+                        case "audout:u": Service = new ServiceAudOut();   break;
+                        case "audren:u": Service = new ServiceAudRen();   break;
+                        case "bsd:u":    Service = new ServiceBsd();      break;
+                        case "friend:a": Service = new ServiceFriend();   break;
+                        case "fsp-srv":  Service = new ServiceFspSrv();   break;
+                        case "hid":      Service = new ServiceHid();      break;
+                        case "lm":       Service = new ServiceLm();       break;
+                        case "nifm:u":   Service = new ServiceNifm();     break;
+                        case "nvdrv":    Service = new ServiceNvDrv();    break;
+                        case "nvdrv:a":  Service = new ServiceNvDrv();    break;
+                        case "pctl:a":   Service = new ServicePctl();     break;
+                        case "pl:u":     Service = new ServicePl();       break;
+                        case "set":      Service = new ServiceSet();      break;
+                        case "set:sys":  Service = new ServiceSetSys();   break;
+                        case "sfdnsres": Service = new ServiceSfdnsres(); break;
+                        case "sm:":      Service = new ServiceSm();       break;
+                        case "ssl":      Service = new ServiceSsl();      break;
+                        case "time:s":   Service = new ServiceTime();     break;
+                        case "time:u":   Service = new ServiceTime();     break;
+                        case "vi:m":     Service = new ServiceVi();       break;
+                        case "vi:s":     Service = new ServiceVi();       break;
+                        case "vi:u":     Service = new ServiceVi();       break;
+                    }
+
+                    if (Service == null)
+                    {
+                        throw new NotImplementedException(Name);
+                    }
+
+                    Services.Add(Name, Service);
+                }
+
+                return Service;
+            }
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                lock (Services)
+                {
+                    foreach (IIpcService Service in Services.Values)
+                    {
+                        if (Service is IDisposable DisposableSrv)
+                        {
+                            DisposableSrv.Dispose();
+                        }
+                    }
+
+                    Services.Clear();
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs
index c58d9e804c..2312920f6c 100644
--- a/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs
+++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioOut.cs
@@ -139,7 +139,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
 
         public long RegisterBufferEvent(ServiceCtx Context)
         {
-            int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent());
+            int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs
index bfde0b65b1..4d29371fbd 100644
--- a/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs
+++ b/Ryujinx.Core/OsHle/Services/Aud/IAudioRenderer.cs
@@ -56,7 +56,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Aud
 
         public long QuerySystemEvent(ServiceCtx Context)
         {
-            int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent());
+            int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs
index d22e0ff23b..ef437c022f 100644
--- a/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs
+++ b/Ryujinx.Core/OsHle/Services/Hid/IAppletResource.cs
@@ -10,21 +10,23 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
 
         public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
-        private HSharedMem Handle;
+        private HSharedMem HidSharedMem;
 
-        public IAppletResource(HSharedMem Handle)
+        public IAppletResource(HSharedMem HidSharedMem)
         {
             m_Commands = new Dictionary<int, ServiceProcessRequest>()
             {
                 { 0, GetSharedMemoryHandle }
             };
 
-            this.Handle = Handle;
+            this.HidSharedMem = HidSharedMem;
         }
 
-        public static long GetSharedMemoryHandle(ServiceCtx Context)
+        public long GetSharedMemoryHandle(ServiceCtx Context)
         {
-            Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.HidHandle);
+            int Handle = Context.Process.HandleTable.OpenHandle(HidSharedMem);
+
+            Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
             return 0;
         }
diff --git a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs
index cc30a771e0..b1f930725f 100644
--- a/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs
+++ b/Ryujinx.Core/OsHle/Services/Hid/ServiceHid.cs
@@ -1,4 +1,3 @@
-using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
 using System.Collections.Generic;
 
@@ -32,9 +31,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
 
         public long CreateAppletResource(ServiceCtx Context)
         {
-            HSharedMem HidHndData = Context.Ns.Os.Handles.GetData<HSharedMem>(Context.Ns.Os.HidHandle);
-
-            MakeObject(Context, new IAppletResource(HidHndData));
+            MakeObject(Context, new IAppletResource(Context.Ns.Os.HidSharedMem));
 
             return 0;
         }
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs b/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs
new file mode 100644
index 0000000000..dbce74adfc
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvFd.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Core.OsHle.IpcServices.NvServices
+{
+    class NvFd
+    {
+        public string Name { get; private set; }
+
+        public NvFd(string Name)
+        {
+            this.Name = Name;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs
new file mode 100644
index 0000000000..ca844f9f28
--- /dev/null
+++ b/Ryujinx.Core/OsHle/Services/Nv/NvMap.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Core.OsHle.IpcServices.NvServices
+{
+    class NvMap
+    {
+        public int  Handle;
+        public int  Id;
+        public int  Size;
+        public int  Align;
+        public int  Kind;
+        public long Address;
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs
index 3c0c46fec9..67ad44919a 100644
--- a/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs
+++ b/Ryujinx.Core/OsHle/Services/Nv/ServiceNvDrv.cs
@@ -1,5 +1,4 @@
 using ChocolArm64.Memory;
-using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
 using Ryujinx.Core.OsHle.Utilities;
 using Ryujinx.Graphics.Gpu;
@@ -12,41 +11,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
     {
         private delegate long ServiceProcessIoctl(ServiceCtx Context);
 
-        private static Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds =
-                   new Dictionary<(string, int), ServiceProcessIoctl>()
-        {
-            { ("/dev/nvhost-as-gpu",   0x4101), NvGpuAsIoctlBindChannel           },
-            { ("/dev/nvhost-as-gpu",   0x4102), NvGpuAsIoctlAllocSpace            },
-            { ("/dev/nvhost-as-gpu",   0x4106), NvGpuAsIoctlMapBufferEx           },
-            { ("/dev/nvhost-as-gpu",   0x4108), NvGpuAsIoctlGetVaRegions          },
-            { ("/dev/nvhost-as-gpu",   0x4109), NvGpuAsIoctlInitializeEx          },
-            { ("/dev/nvhost-ctrl",     0x001b), NvHostIoctlCtrlGetConfig          },
-            { ("/dev/nvhost-ctrl",     0x001d), NvHostIoctlCtrlEventWait          },
-            { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize         },
-            { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo            },
-            { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics      },
-            { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks             },
-            { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask    },
-            { ("/dev/nvhost-gpu",      0x4714), NvMapIoctlChannelSetUserData      },
-            { ("/dev/nvhost-gpu",      0x4801), NvMapIoctlChannelSetNvMap         },
-            { ("/dev/nvhost-gpu",      0x4808), NvMapIoctlChannelSubmitGpFifo     },
-            { ("/dev/nvhost-gpu",      0x4809), NvMapIoctlChannelAllocObjCtx      },
-            { ("/dev/nvhost-gpu",      0x480b), NvMapIoctlChannelZcullBind        },
-            { ("/dev/nvhost-gpu",      0x480c), NvMapIoctlChannelSetErrorNotifier },
-            { ("/dev/nvhost-gpu",      0x480d), NvMapIoctlChannelSetPriority      },
-            { ("/dev/nvhost-gpu",      0x481a), NvMapIoctlChannelAllocGpFifoEx2   },
-            { ("/dev/nvmap",           0x0101), NvMapIocCreate                    },
-            { ("/dev/nvmap",           0x0103), NvMapIocFromId                    },
-            { ("/dev/nvmap",           0x0104), NvMapIocAlloc                     },
-            { ("/dev/nvmap",           0x0105), NvMapIocFree                      },
-            { ("/dev/nvmap",           0x0109), NvMapIocParam                     },
-            { ("/dev/nvmap",           0x010e), NvMapIocGetId                     },
-        };
-
         private Dictionary<int, ServiceProcessRequest> m_Commands;
 
         public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
+        private Dictionary<(string, int), ServiceProcessIoctl> IoctlCmds;
+
+        private IdDictionary Fds;
+
+        private IdDictionary NvMaps;
+        private IdDictionary NvMapsById;
+
         public ServiceNvDrv()
         {
             m_Commands = new Dictionary<int, ServiceProcessRequest>()
@@ -58,15 +33,50 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
                 { 4, QueryEvent   },
                 { 8, SetClientPid },
             };
+
+            IoctlCmds = new Dictionary<(string, int), ServiceProcessIoctl>()
+            {
+                { ("/dev/nvhost-as-gpu",   0x4101), NvGpuAsIoctlBindChannel           },
+                { ("/dev/nvhost-as-gpu",   0x4102), NvGpuAsIoctlAllocSpace            },
+                { ("/dev/nvhost-as-gpu",   0x4106), NvGpuAsIoctlMapBufferEx           },
+                { ("/dev/nvhost-as-gpu",   0x4108), NvGpuAsIoctlGetVaRegions          },
+                { ("/dev/nvhost-as-gpu",   0x4109), NvGpuAsIoctlInitializeEx          },
+                { ("/dev/nvhost-ctrl",     0x001b), NvHostIoctlCtrlGetConfig          },
+                { ("/dev/nvhost-ctrl",     0x001d), NvHostIoctlCtrlEventWait          },
+                { ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize         },
+                { ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo            },
+                { ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics      },
+                { ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks             },
+                { ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask    },
+                { ("/dev/nvhost-gpu",      0x4714), NvMapIoctlChannelSetUserData      },
+                { ("/dev/nvhost-gpu",      0x4801), NvMapIoctlChannelSetNvMap         },
+                { ("/dev/nvhost-gpu",      0x4808), NvMapIoctlChannelSubmitGpFifo     },
+                { ("/dev/nvhost-gpu",      0x4809), NvMapIoctlChannelAllocObjCtx      },
+                { ("/dev/nvhost-gpu",      0x480b), NvMapIoctlChannelZcullBind        },
+                { ("/dev/nvhost-gpu",      0x480c), NvMapIoctlChannelSetErrorNotifier },
+                { ("/dev/nvhost-gpu",      0x480d), NvMapIoctlChannelSetPriority      },
+                { ("/dev/nvhost-gpu",      0x481a), NvMapIoctlChannelAllocGpFifoEx2   },
+                { ("/dev/nvmap",           0x0101), NvMapIocCreate                    },
+                { ("/dev/nvmap",           0x0103), NvMapIocFromId                    },
+                { ("/dev/nvmap",           0x0104), NvMapIocAlloc                     },
+                { ("/dev/nvmap",           0x0105), NvMapIocFree                      },
+                { ("/dev/nvmap",           0x0109), NvMapIocParam                     },
+                { ("/dev/nvmap",           0x010e), NvMapIocGetId                     },
+            };
+
+            Fds = new IdDictionary();
+
+            NvMaps     = new IdDictionary();
+            NvMapsById = new IdDictionary();
         }
 
-        public static long Open(ServiceCtx Context)
+        public long Open(ServiceCtx Context)
         {
             long NamePtr = Context.Request.SendBuff[0].Position;
 
             string Name = AMemoryHelper.ReadAsciiString(Context.Memory, NamePtr);
 
-            int Fd = Context.Ns.Os.Fds.GenerateId(new FileDesc(Name));
+            int Fd = Fds.Add(new NvFd(Name));
 
             Context.ResponseData.Write(Fd);
             Context.ResponseData.Write(0);
@@ -74,12 +84,12 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        public static long Ioctl(ServiceCtx Context)
+        public long Ioctl(ServiceCtx Context)
         {
             int Fd  = Context.RequestData.ReadInt32();
             int Cmd = Context.RequestData.ReadInt32() & 0xffff;
             
-            FileDesc FdData = Context.Ns.Os.Fds.GetData<FileDesc>(Fd);
+            NvFd FdData = Fds.GetData<NvFd>(Fd);
 
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -95,18 +105,18 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             }
         }
 
-        public static long Close(ServiceCtx Context)
+        public long Close(ServiceCtx Context)
         {
             int Fd = Context.RequestData.ReadInt32();
 
-            Context.Ns.Os.Fds.Delete(Fd);
+            Fds.Delete(Fd);
 
             Context.ResponseData.Write(0);
 
             return 0;
         }
 
-        public static long Initialize(ServiceCtx Context)
+        public long Initialize(ServiceCtx Context)
         {
             long TransferMemSize   = Context.RequestData.ReadInt64();
             int  TransferMemHandle = Context.Request.HandleDesc.ToCopy[0];
@@ -116,7 +126,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        public static long QueryEvent(ServiceCtx Context)
+        public long QueryEvent(ServiceCtx Context)
         {
             int Fd      = Context.RequestData.ReadInt32();
             int EventId = Context.RequestData.ReadInt32();
@@ -128,7 +138,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        public static long SetClientPid(ServiceCtx Context)
+        public long SetClientPid(ServiceCtx Context)
         {
             long Pid = Context.RequestData.ReadInt64();
 
@@ -137,7 +147,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuAsIoctlBindChannel(ServiceCtx Context)
+        private long NvGpuAsIoctlBindChannel(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -146,7 +156,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuAsIoctlAllocSpace(ServiceCtx Context)
+        private long NvGpuAsIoctlAllocSpace(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -172,7 +182,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuAsIoctlMapBufferEx(ServiceCtx Context)
+        private long NvGpuAsIoctlMapBufferEx(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -186,18 +196,29 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             long MapSize  = Reader.ReadInt64();
             long Offset   = Reader.ReadInt64();
 
-            HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
-
-            if (NvMap != null)
+            if (Handle == 0)
             {
-                if ((Flags & 1) != 0)
-                {
-                    Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, Offset, NvMap.Size);
-                }
-                else
-                {
-                    Offset = Context.Ns.Gpu.MapMemory(NvMap.Address, NvMap.Size);
-                }
+                //Handle 0 is valid here, but it refers to something else.
+                //TODO: Figure out what, for now just return success.
+                return 0;
+            }
+
+            NvMap Map = NvMaps.GetData<NvMap>(Handle);
+
+            if (Map == null)
+            {
+                Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+                
+                return -1; //TODO: Corrent error code.
+            }
+
+            if ((Flags & 1) != 0)
+            {
+                Offset = Context.Ns.Gpu.MapMemory(Map.Address, Offset, Map.Size);
+            }
+            else
+            {
+                Offset = Context.Ns.Gpu.MapMemory(Map.Address, Map.Size);
             }
 
             Context.Memory.WriteInt64(Position + 0x20, Offset);
@@ -205,7 +226,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuAsIoctlGetVaRegions(ServiceCtx Context)
+        private long NvGpuAsIoctlGetVaRegions(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -235,7 +256,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuAsIoctlInitializeEx(ServiceCtx Context)
+        private long NvGpuAsIoctlInitializeEx(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -252,7 +273,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
+        private long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -267,7 +288,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvHostIoctlCtrlEventWait(ServiceCtx Context)
+        private long NvHostIoctlCtrlEventWait(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -283,7 +304,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context)
+        private long NvGpuIoctlZcullGetCtxSize(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -292,7 +313,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuIoctlZcullGetInfo(ServiceCtx Context)
+        private long NvGpuIoctlZcullGetInfo(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -312,7 +333,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
+        private long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -374,7 +395,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuIoctlGetTpcMasks(ServiceCtx Context)
+        private long NvGpuIoctlGetTpcMasks(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -388,7 +409,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context)
+        private long NvGpuIoctlZbcGetActiveSlotMask(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -398,14 +419,14 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIoctlChannelSetUserData(ServiceCtx Context)
+        private long NvMapIoctlChannelSetUserData(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
             return 0;
         }
 
-        private static long NvMapIoctlChannelSetNvMap(ServiceCtx Context)
+        private long NvMapIoctlChannelSetNvMap(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -414,7 +435,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context)
+        private long NvMapIoctlChannelSubmitGpFifo(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -453,7 +474,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context)
+        private long NvMapIoctlChannelAllocObjCtx(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -465,7 +486,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIoctlChannelZcullBind(ServiceCtx Context)
+        private long NvMapIoctlChannelZcullBind(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -478,7 +499,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context)
+        private long NvMapIoctlChannelSetErrorNotifier(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -492,7 +513,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIoctlChannelSetPriority(ServiceCtx Context)
+        private long NvMapIoctlChannelSetPriority(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -501,7 +522,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context)
+        private long NvMapIoctlChannelAllocGpFifoEx2(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -521,47 +542,46 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIocCreate(ServiceCtx Context)
+        private long NvMapIocCreate(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
             int Size = Context.Memory.ReadInt32(Position);
 
-            int Id = Context.Ns.Os.NvMapIds.GenerateId();
+            NvMap Map = new NvMap() { Size = Size };
 
-            int Handle = Context.Ns.Os.Handles.GenerateId(new HNvMap(Id, Size));
+            Map.Handle = NvMaps.Add(Map);
 
-            Context.Memory.WriteInt32(Position + 4, Handle);
+            Map.Id = NvMapsById.Add(Map);
 
-            Logging.Info($"NvMap {Id} created with size {Size:x8}!");
+            Context.Memory.WriteInt32(Position + 4, Map.Handle);
+
+            Logging.Info($"NvMap {Map.Id} created with size {Size:x8}!");
 
             return 0;
         }
 
-        private static long NvMapIocFromId(ServiceCtx Context)
+        private long NvMapIocFromId(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
             int Id = Context.Memory.ReadInt32(Position);
 
-            int Handle = -1;
+            NvMap Map = NvMapsById.GetData<NvMap>(Id);
 
-            foreach (KeyValuePair<int, object> KV in Context.Ns.Os.Handles)
+            if (Map == null)
             {
-                if (KV.Value is HNvMap NvMap && NvMap.Id == Id)
-                {
-                    Handle = KV.Key;
-
-                    break;
-                }
+                Logging.Warn($"Trying to use invalid NvMap Id {Id}!");
+                
+                return -1; //TODO: Corrent error code.
             }
 
-            Context.Memory.WriteInt32(Position + 4, Handle);
+            Context.Memory.WriteInt32(Position + 4, Map.Handle);
 
             return 0;
         }
 
-        private static long NvMapIocAlloc(ServiceCtx Context)
+        private long NvMapIocAlloc(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -574,38 +594,49 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             byte Kind     = (byte)Reader.ReadInt64();
             long Addr     =       Reader.ReadInt64();
 
-            HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Handle);
 
-            if (NvMap != null)
+            if (Map == null)
             {
-                NvMap.Address = Addr;
-                NvMap.Align   = Align;
-                NvMap.Kind    = Kind;
+                Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+                
+                return -1; //TODO: Corrent error code.
             }
 
+            Map.Address = Addr;
+            Map.Align   = Align;
+            Map.Kind    = Kind;
+
             return 0;
         }
 
-        private static long NvMapIocFree(ServiceCtx Context)
+        private long NvMapIocFree(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
             MemReader Reader = new MemReader(Context.Memory, Position);
             MemWriter Writer = new MemWriter(Context.Memory, Position + 8);
 
-            int  Handle  =       Reader.ReadInt32();
-            int  Padding =       Reader.ReadInt32();
+            int  Handle  = Reader.ReadInt32();
+            int  Padding = Reader.ReadInt32();
 
-            HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Handle);
+
+            if (Map == null)
+            {
+                Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+                
+                return -1; //TODO: Corrent error code.
+            }
 
             Writer.WriteInt64(0);
-            Writer.WriteInt32(NvMap.Size);
+            Writer.WriteInt32(Map.Size);
             Writer.WriteInt32(0);
 
             return 0;
         }
 
-        private static long NvMapIocParam(ServiceCtx Context)
+        private long NvMapIocParam(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
@@ -614,16 +645,23 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             int Handle = Reader.ReadInt32();
             int Param  = Reader.ReadInt32();
 
-            HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Handle);
+
+            if (Map == null)
+            {
+                Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+                
+                return -1; //TODO: Corrent error code.
+            }
 
             int Response = 0;
-            
+
             switch (Param)
             {
-                case 1: Response = NvMap.Size;  break;
-                case 2: Response = NvMap.Align; break;
-                case 4: Response = 0x40000000;  break;
-                case 5: Response = NvMap.Kind;  break;
+                case 1: Response = Map.Size;   break;
+                case 2: Response = Map.Align;  break;
+                case 4: Response = 0x40000000; break;
+                case 5: Response = Map.Kind;   break;
             }
 
             Context.Memory.WriteInt32(Position + 8, Response);
@@ -631,17 +669,29 @@ namespace Ryujinx.Core.OsHle.IpcServices.NvServices
             return 0;
         }
 
-        private static long NvMapIocGetId(ServiceCtx Context)
+        private long NvMapIocGetId(ServiceCtx Context)
         {
             long Position = Context.Request.GetSendBuffPtr();
 
             int Handle = Context.Memory.ReadInt32(Position + 4);
 
-            HNvMap NvMap = Context.Ns.Os.Handles.GetData<HNvMap>(Handle);
+            NvMap Map = NvMaps.GetData<NvMap>(Handle);
 
-            Context.Memory.WriteInt32(Position, NvMap.Id);
+            if (Map == null)
+            {
+                Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
+                
+                return -1; //TODO: Corrent error code.
+            }
+
+            Context.Memory.WriteInt32(Position, Map.Id);
 
             return 0;
         }
+
+        public NvMap GetNvMap(int Handle)
+        {
+            return NvMaps.GetData<NvMap>(Handle);
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/ObjHelper.cs b/Ryujinx.Core/OsHle/Services/ObjHelper.cs
index ff71838a69..89d986aeb0 100644
--- a/Ryujinx.Core/OsHle/Services/ObjHelper.cs
+++ b/Ryujinx.Core/OsHle/Services/ObjHelper.cs
@@ -9,13 +9,13 @@ namespace Ryujinx.Core.OsHle.IpcServices
         {
             if (Context.Session is HDomain Dom)
             {
-                Context.Response.ResponseObjIds.Add(Dom.GenerateObjectId(Obj));
+                Context.Response.ResponseObjIds.Add(Dom.Add(Obj));
             }
             else
             {
                 HSessionObj HndData = new HSessionObj(Context.Session, Obj);
 
-                int VHandle = Context.Ns.Os.Handles.GenerateId(HndData);
+                int VHandle = Context.Process.HandleTable.OpenHandle(HndData);
 
                 Context.Response.HandleDesc = IpcHandleDesc.MakeMove(VHandle);
             }
diff --git a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs
index abc34ed213..bb795f3f49 100644
--- a/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs
+++ b/Ryujinx.Core/OsHle/Services/Pl/ServicePl.cs
@@ -20,30 +20,32 @@ namespace Ryujinx.Core.OsHle.IpcServices.Pl
             };
         }
 
-        public static long GetLoadState(ServiceCtx Context)
+        public long GetLoadState(ServiceCtx Context)
         {
             Context.ResponseData.Write(1); //Loaded
 
             return 0;
         }
 
-        public static long GetFontSize(ServiceCtx Context)
+        public long GetFontSize(ServiceCtx Context)
         {
             Context.ResponseData.Write(Horizon.FontSize);
 
             return 0;
         }
 
-        public static long GetSharedMemoryAddressOffset(ServiceCtx Context)
+        public long GetSharedMemoryAddressOffset(ServiceCtx Context)
         {
             Context.ResponseData.Write(0);
 
             return 0;
         }
 
-        public static long GetSharedMemoryNativeHandle(ServiceCtx Context)
+        public long GetSharedMemoryNativeHandle(ServiceCtx Context)
         {
-            Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Context.Ns.Os.FontHandle);
+            int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.FontSharedMem);
+
+            Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
             return 0;
         }
diff --git a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs b/Ryujinx.Core/OsHle/Services/ServiceFactory.cs
deleted file mode 100644
index 2b855d25b7..0000000000
--- a/Ryujinx.Core/OsHle/Services/ServiceFactory.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using Ryujinx.Core.OsHle.IpcServices.Acc;
-using Ryujinx.Core.OsHle.IpcServices.Am;
-using Ryujinx.Core.OsHle.IpcServices.Apm;
-using Ryujinx.Core.OsHle.IpcServices.Aud;
-using Ryujinx.Core.OsHle.IpcServices.Bsd;
-using Ryujinx.Core.OsHle.IpcServices.Friend;
-using Ryujinx.Core.OsHle.IpcServices.FspSrv;
-using Ryujinx.Core.OsHle.IpcServices.Hid;
-using Ryujinx.Core.OsHle.IpcServices.Lm;
-using Ryujinx.Core.OsHle.IpcServices.Nifm;
-using Ryujinx.Core.OsHle.IpcServices.Ns;
-using Ryujinx.Core.OsHle.IpcServices.NvServices;
-using Ryujinx.Core.OsHle.IpcServices.Pctl;
-using Ryujinx.Core.OsHle.IpcServices.Pl;
-using Ryujinx.Core.OsHle.IpcServices.Set;
-using Ryujinx.Core.OsHle.IpcServices.Sfdnsres;
-using Ryujinx.Core.OsHle.IpcServices.Sm;
-using Ryujinx.Core.OsHle.IpcServices.Ssl;
-using Ryujinx.Core.OsHle.IpcServices.Time;
-using Ryujinx.Core.OsHle.IpcServices.Vi;
-using System;
-
-namespace Ryujinx.Core.OsHle.IpcServices
-{
-    static class ServiceFactory
-    {
-        public static IIpcService MakeService(string Name)
-        {
-            switch (Name)
-            {
-                case "acc:u0":   return new ServiceAcc();
-                case "aoc:u":    return new ServiceNs();
-                case "apm":      return new ServiceApm();
-                case "apm:p":    return new ServiceApm();
-                case "appletOE": return new ServiceAppletOE();
-                case "audout:u": return new ServiceAudOut();
-                case "audren:u": return new ServiceAudRen();
-                case "bsd:s":    return new ServiceBsd();
-                case "bsd:u":    return new ServiceBsd();
-                case "friend:a": return new ServiceFriend();
-                case "fsp-srv":  return new ServiceFspSrv();
-                case "hid":      return new ServiceHid();
-                case "lm":       return new ServiceLm();
-                case "nifm:u":   return new ServiceNifm();
-                case "nvdrv":    return new ServiceNvDrv();
-                case "nvdrv:a":  return new ServiceNvDrv();
-                case "pctl:a":   return new ServicePctl();
-                case "pl:u":     return new ServicePl();
-                case "set":      return new ServiceSet();
-                case "set:sys":  return new ServiceSetSys();
-                case "sfdnsres": return new ServiceSfdnsres();
-                case "sm:":      return new ServiceSm();
-                case "ssl":      return new ServiceSsl();
-                case "time:s":   return new ServiceTime();
-                case "time:u":   return new ServiceTime();
-                case "vi:m":     return new ServiceVi();
-                case "vi:s":     return new ServiceVi();
-                case "vi:u":     return new ServiceVi();
-            }
-
-            throw new NotImplementedException(Name);
-        }
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs
index a5f1b329b8..cb745e3738 100644
--- a/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs
+++ b/Ryujinx.Core/OsHle/Services/Sm/ServiceSm.cs
@@ -55,9 +55,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Sm
                 return 0;
             }
 
-            HSession Session = new HSession(ServiceFactory.MakeService(Name));
+            HSession Session = new HSession(Context.Process.Services.GetService(Name));
 
-            int Handle = Context.Ns.Os.Handles.GenerateId(Session);
+            int Handle = Context.Process.HandleTable.OpenHandle(Session);
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
 
diff --git a/Ryujinx.Core/OsHle/Display.cs b/Ryujinx.Core/OsHle/Services/Vi/Display.cs
similarity index 79%
rename from Ryujinx.Core/OsHle/Display.cs
rename to Ryujinx.Core/OsHle/Services/Vi/Display.cs
index 590841fc50..ceadc39311 100644
--- a/Ryujinx.Core/OsHle/Display.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/Display.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Core.OsHle
+namespace Ryujinx.Core.OsHle.IpcServices.Vi
 {
     class Display
     {
diff --git a/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs
index 4e40b99b3d..0ff1f90993 100644
--- a/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/IApplicationDisplayService.cs
@@ -15,6 +15,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
 
         public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
 
+        private IdDictionary Displays;
+
         public IApplicationDisplayService()
         {
             m_Commands = new Dictionary<int, ServiceProcessRequest>()
@@ -28,14 +30,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
                 { 2020, OpenLayer                            },
                 { 2021, CloseLayer                           },
                 { 2030, CreateStrayLayer                     },
+                { 2031, DestroyStrayLayer                    },
                 { 2101, SetLayerScalingMode                  },
                 { 5202, GetDisplayVSyncEvent                 }
             };
+
+            Displays = new IdDictionary();
         }
 
         public long GetRelayService(ServiceCtx Context)
         {
-            MakeObject(Context, new IHOSBinderDriver());
+            MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer));
 
             return 0;
         }
@@ -56,7 +61,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
 
         public long GetIndirectDisplayTransactionService(ServiceCtx Context)
         {
-            MakeObject(Context, new IHOSBinderDriver());
+            MakeObject(Context, new IHOSBinderDriver(Context.Ns.Gpu.Renderer));
 
             return 0;
         }
@@ -65,7 +70,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
         {
             string Name = GetDisplayName(Context);
 
-            long DisplayId = Context.Ns.Os.Displays.GenerateId(new Display(Name));
+            long DisplayId = Displays.Add(new Display(Name));
 
             Context.ResponseData.Write(DisplayId);
 
@@ -76,7 +81,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
         {
             int DisplayId = Context.RequestData.ReadInt32();
 
-            Context.Ns.Os.Displays.Delete(DisplayId);
+            Displays.Delete(DisplayId);
 
             return 0;
         }
@@ -99,6 +104,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
 
         public long CloseLayer(ServiceCtx Context)
         {
+            long LayerId = Context.RequestData.ReadInt64();
+
             return 0;
         }
 
@@ -109,7 +116,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
 
             long ParcelPtr = Context.Request.ReceiveBuff[0].Position;
 
-            Display Disp = Context.Ns.Os.Displays.GetData<Display>((int)DisplayId);
+            Display Disp = Displays.GetData<Display>((int)DisplayId);
 
             byte[] Parcel = MakeIGraphicsBufferProducer(ParcelPtr);
 
@@ -121,6 +128,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
             return 0;
         }
 
+        public long DestroyStrayLayer(ServiceCtx Context)
+        {
+            return 0;
+        }
+
         public long SetLayerScalingMode(ServiceCtx Context)
         {
             int  ScalingMode = Context.RequestData.ReadInt32();
@@ -133,7 +145,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
         {
             string Name = GetDisplayName(Context);
 
-            int Handle = Context.Ns.Os.Handles.GenerateId(new HEvent());
+            int Handle = Context.Process.HandleTable.OpenHandle(new HEvent());
 
             Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
 
diff --git a/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs
index a89c1df824..b24a773bfe 100644
--- a/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/IHOSBinderDriver.cs
@@ -1,6 +1,7 @@
 using ChocolArm64.Memory;
 using Ryujinx.Core.OsHle.Ipc;
 using Ryujinx.Core.OsHle.IpcServices.Android;
+using Ryujinx.Graphics.Gal;
 using System;
 using System.Collections.Generic;
 
@@ -14,7 +15,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
 
         private NvFlinger Flinger;
 
-        public IHOSBinderDriver()
+        public IHOSBinderDriver(IGalRenderer Renderer)
         {
             m_Commands = new Dictionary<int, ServiceProcessRequest>()
             {
@@ -23,7 +24,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Vi
                 { 2, GetNativeHandle }
             };
 
-            Flinger = new NvFlinger();
+            Flinger = new NvFlinger(Renderer);
         }
 
         public long TransactParcel(ServiceCtx Context)
diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
index 1d394fb4a7..5309dcabb7 100644
--- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
+++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs
@@ -1,5 +1,6 @@
 using ChocolArm64.Memory;
-using Ryujinx.Core.OsHle.Handles;
+using Ryujinx.Core.OsHle.IpcServices.NvServices;
+using Ryujinx.Graphics.Gal;
 using System;
 using System.IO;
 using System.Collections.Generic;
@@ -54,18 +55,27 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
             public GbpBuffer Data;
         }
 
+        private IGalRenderer Renderer;
+
         private BufferEntry[] BufferQueue;
 
         private ManualResetEvent WaitBufferFree;
+        
+        private object RenderQueueLock;
+
+        private int RenderQueueCount;
+
+        private bool NvFlingerDisposed;
 
         private bool KeepRunning;
 
-        public NvFlinger()
+        public NvFlinger(IGalRenderer Renderer)
         {
             Commands = new Dictionary<(string, int), ServiceProcessParcel>()
             {
                 { ("android.gui.IGraphicBufferProducer", 0x1), GbpRequestBuffer  },
                 { ("android.gui.IGraphicBufferProducer", 0x3), GbpDequeueBuffer  },
+                { ("android.gui.IGraphicBufferProducer", 0x4), GbpDetachBuffer   },
                 { ("android.gui.IGraphicBufferProducer", 0x7), GbpQueueBuffer    },
                 { ("android.gui.IGraphicBufferProducer", 0x8), GbpCancelBuffer   },
                 { ("android.gui.IGraphicBufferProducer", 0x9), GbpQuery          },
@@ -74,10 +84,14 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
                 { ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
             };
 
+            this.Renderer = Renderer;
+
             BufferQueue = new BufferEntry[0x40];
 
             WaitBufferFree = new ManualResetEvent(false);
 
+            RenderQueueLock = new object();
+
             KeepRunning = true;
         }
 
@@ -193,6 +207,11 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
             return MakeReplyParcel(Context, 1280, 720, 0, 0, 0);
         }
 
+        private long GbpDetachBuffer(ServiceCtx Context, BinaryReader ParcelReader)
+        {
+            return MakeReplyParcel(Context, 0);
+        }
+
         private long GbpCancelBuffer(ServiceCtx Context, BinaryReader ParcelReader)
         {
             //TODO: Errors.
@@ -266,7 +285,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
 
             long FbSize = (uint)FbWidth * FbHeight * 4;
 
-            HNvMap NvMap = GetNvMap(Context, Slot);
+            NvMap NvMap = GetNvMap(Context, Slot);
 
             if ((ulong)(NvMap.Address + FbSize) > AMemoryMgr.AddrSize)
             {
@@ -330,7 +349,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
                 Rotate = -MathF.PI * 0.5f;
             }
 
-            byte* Fb = (byte*)Context.Ns.Memory.Ram + NvMap.Address;
+            lock (RenderQueueLock)
+            {
+                if (NvFlingerDisposed)
+                {
+                    return;
+                }
+
+                Interlocked.Increment(ref RenderQueueCount);
+            }
+
+            byte* Fb = (byte*)Context.Memory.Ram + NvMap.Address;
 
             Context.Ns.Gpu.Renderer.QueueAction(delegate()
             {
@@ -346,6 +375,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
 
                 BufferQueue[Slot].State = BufferState.Free;
 
+                Interlocked.Decrement(ref RenderQueueCount);
+
                 lock (WaitBufferFree)
                 {
                     WaitBufferFree.Set();
@@ -353,7 +384,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
             });
         }
 
-        private HNvMap GetNvMap(ServiceCtx Context, int Slot)
+        private NvMap GetNvMap(ServiceCtx Context, int Slot)
         {
             int NvMapHandle = BitConverter.ToInt32(BufferQueue[Slot].Data.RawData, 0x4c);
 
@@ -366,7 +397,9 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
                 NvMapHandle = BitConverter.ToInt32(RawValue, 0);
             }
 
-            return Context.Ns.Os.Handles.GetData<HNvMap>(NvMapHandle);
+            ServiceNvDrv NvDrv = (ServiceNvDrv)Context.Process.Services.GetService("nvdrv");
+
+            return NvDrv.GetNvMap(NvMapHandle);
         }
 
         private int GetFreeSlotBlocking(int Width, int Height)
@@ -432,10 +465,24 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android
             Dispose(true);
         }
 
-        protected virtual void Dispose(bool disposing)
+        protected virtual void Dispose(bool Disposing)
         {
-            if (disposing)
+            if (Disposing && !NvFlingerDisposed)
             {
+                lock (RenderQueueLock)
+                {
+                    NvFlingerDisposed = true;
+                }
+
+                //Ensure that all pending actions was sent before
+                //we can safely assume that the class was disposed.
+                while (RenderQueueCount > 0)
+                {
+                    Thread.Yield();
+                }
+
+                Renderer.ResetFrameBuffer();
+
                 lock (WaitBufferFree)
                 {
                     KeepRunning = false;
diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
index b3e6262db1..3ce56a3cd7 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
@@ -1,12 +1,13 @@
 using ChocolArm64.Events;
 using ChocolArm64.Memory;
 using ChocolArm64.State;
+using Ryujinx.Core.OsHle.Handles;
 using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.Core.OsHle.Svc
 {
-    partial class SvcHandler
+    partial class SvcHandler : IDisposable
     {
         private delegate void SvcFunc(AThreadState ThreadState);
 
@@ -16,10 +17,12 @@ namespace Ryujinx.Core.OsHle.Svc
         private Process Process;
         private AMemory Memory;
 
-        private static Random Rng;
-        
+        private HashSet<(HSharedMem, long)> MappedSharedMems;
+
         private ulong CurrentHeapSize;
 
+        private static Random Rng;
+
         public SvcHandler(Switch Ns, Process Process)
         {
             SvcFuncs = new Dictionary<int, SvcFunc>()
@@ -32,6 +35,7 @@ namespace Ryujinx.Core.OsHle.Svc
                 { 0x07, SvcExitProcess                   },
                 { 0x08, SvcCreateThread                  },
                 { 0x09, SvcStartThread                   },
+                { 0x0a, SvcExitThread                    },
                 { 0x0b, SvcSleepThread                   },
                 { 0x0c, SvcGetThreadPriority             },
                 { 0x0d, SvcSetThreadPriority             },
@@ -60,6 +64,8 @@ namespace Ryujinx.Core.OsHle.Svc
             this.Ns      = Ns;
             this.Process = Process;
             this.Memory  = Process.Memory;
+
+            MappedSharedMems = new HashSet<(HSharedMem, long)>();
         }
 
         static SvcHandler()
@@ -84,5 +90,26 @@ namespace Ryujinx.Core.OsHle.Svc
                 throw new NotImplementedException(e.Id.ToString("x4"));
             }
         }
+
+        public void Dispose()
+        {
+            Dispose(true);
+        }
+
+        protected virtual void Dispose(bool Disposing)
+        {
+            if (Disposing)
+            {
+                lock (MappedSharedMems)
+                {
+                    foreach ((HSharedMem SharedMem, long Position) in MappedSharedMems)
+                    {
+                        SharedMem.RemoveVirtualPosition(Memory, Position);
+                    }
+
+                    MappedSharedMems.Clear();
+                }
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs
index c15f449bf1..80f24d2bd5 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcMemory.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcMemory.cs
@@ -165,7 +165,7 @@ namespace Ryujinx.Core.OsHle.Svc
                 return;
             }
 
-            HSharedMem SharedMem = Ns.Os.Handles.GetData<HSharedMem>(Handle);
+            HSharedMem SharedMem = Process.HandleTable.GetData<HSharedMem>(Handle);
 
             if (SharedMem != null)
             {
@@ -175,7 +175,12 @@ namespace Ryujinx.Core.OsHle.Svc
 
                 Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
 
-                SharedMem.AddVirtualPosition(Src);
+                lock (MappedSharedMems)
+                {
+                    MappedSharedMems.Add((SharedMem, Src));
+                }
+
+                SharedMem.AddVirtualPosition(Memory, Src);
 
                 ThreadState.X0 = 0;
             }
@@ -198,12 +203,19 @@ namespace Ryujinx.Core.OsHle.Svc
                 return;
             }
 
-            HSharedMem HndData = Ns.Os.Handles.GetData<HSharedMem>(Handle);
+            HSharedMem SharedMem = Process.HandleTable.GetData<HSharedMem>(Handle);
 
-            if (HndData != null)
+            if (SharedMem != null)
             {
                 Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory);
 
+                SharedMem.RemoveVirtualPosition(Memory, Src);
+
+                lock (MappedSharedMems)
+                {
+                    MappedSharedMems.Remove((SharedMem, Src));
+                }
+
                 ThreadState.X0 = 0;
             }
 
@@ -229,12 +241,12 @@ namespace Ryujinx.Core.OsHle.Svc
 
             Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
 
-            HTransferMem HndData = new HTransferMem(Memory, MapInfo.Perm, Src, Size);
+            HTransferMem TMem = new HTransferMem(Memory, MapInfo.Perm, Src, Size);
 
-            int Handle = Ns.Os.Handles.GenerateId(HndData);
-
-            ThreadState.X1 = (ulong)Handle;
+            ulong Handle = (ulong)Process.HandleTable.OpenHandle(TMem);
+            
             ThreadState.X0 = 0;
+            ThreadState.X1 = Handle;
         }
 
         private static bool IsValidPosition(long Position)
diff --git a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs
index f700903526..671a32d361 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcSystem.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcSystem.cs
@@ -3,7 +3,6 @@ using ChocolArm64.State;
 using Ryujinx.Core.OsHle.Exceptions;
 using Ryujinx.Core.OsHle.Handles;
 using Ryujinx.Core.OsHle.Ipc;
-using Ryujinx.Core.OsHle.IpcServices;
 using System;
 using System.Threading;
 
@@ -35,7 +34,7 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X0;
 
-            Ns.Os.CloseHandle(Handle);
+            Process.HandleTable.CloseHandle(Handle);
 
             ThreadState.X0 = 0;
         }
@@ -80,10 +79,12 @@ namespace Ryujinx.Core.OsHle.Svc
             //TODO: Validate that app has perms to access the service, and that the service
             //actually exists, return error codes otherwise.
 
-            HSession Session = new HSession(ServiceFactory.MakeService(Name));
+            HSession Session = new HSession(Process.Services.GetService(Name));
 
-            ThreadState.X1 = (ulong)Ns.Os.Handles.GenerateId(Session);
+            ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
+            
             ThreadState.X0 = 0;
+            ThreadState.X1 = Handle;
         }
 
         private void SvcSendSyncRequest(AThreadState ThreadState)
@@ -119,13 +120,21 @@ namespace Ryujinx.Core.OsHle.Svc
 
             byte[] CmdData = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
 
-            HSession Session = Ns.Os.Handles.GetData<HSession>(Handle);
+            HSession Session = Process.HandleTable.GetData<HSession>(Handle);
 
             IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr, Session is HDomain);
 
             if (Session != null)
             {
-                IpcHandler.IpcCall(Ns, Memory, Session, Cmd, ThreadState.ThreadId, CmdPtr, Handle);
+                IpcHandler.IpcCall(
+                    Ns,
+                    Process,
+                    Memory,
+                    Session,
+                    Cmd,
+                    ThreadState.ThreadId,
+                    CmdPtr,
+                    Handle);
 
                 byte[] Response = AMemoryHelper.ReadBytes(Memory, CmdPtr, (int)Size);
 
diff --git a/Ryujinx.Core/OsHle/Svc/SvcThread.cs b/Ryujinx.Core/OsHle/Svc/SvcThread.cs
index 6afd2e6106..231ee2a237 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcThread.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcThread.cs
@@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X0;
 
-            HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+            HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
 
             if (Thread != null)
             {
@@ -51,6 +51,13 @@ namespace Ryujinx.Core.OsHle.Svc
             //TODO: Error codes.
         }
 
+        private void SvcExitThread(AThreadState ThreadState)
+        {
+            HThread CurrThread = Process.GetThread(ThreadState.Tpidr);
+            
+            CurrThread.Thread.StopExecution();
+        }
+
         private void SvcSleepThread(AThreadState ThreadState)
         {           
             ulong NanoSecs = ThreadState.X0;
@@ -71,7 +78,7 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X1;
 
-            HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+            HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
 
             if (Thread != null)
             {
@@ -87,7 +94,7 @@ namespace Ryujinx.Core.OsHle.Svc
             int Handle = (int)ThreadState.X1;
             int Prio = (int)ThreadState.X0;
 
-            HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+            HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
 
             if (Thread != null)
             {
@@ -110,7 +117,7 @@ namespace Ryujinx.Core.OsHle.Svc
         {
             int Handle = (int)ThreadState.X0;
 
-            HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
+            HThread Thread = Process.HandleTable.GetData<HThread>(Handle);
 
             if (Thread != null)
             {
diff --git a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
index 6e488da589..38356073e6 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcThreadSync.cs
@@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Svc
             long MutexAddress           = (long)ThreadState.X1;
             int  RequestingThreadHandle =  (int)ThreadState.X2;
 
-            HThread RequestingThread = Ns.Os.Handles.GetData<HThread>(RequestingThreadHandle);
+            HThread RequestingThread = Process.HandleTable.GetData<HThread>(RequestingThreadHandle);
 
             Mutex M = new Mutex(Process, MutexAddress, OwnerThreadHandle);
 
@@ -43,7 +43,7 @@ namespace Ryujinx.Core.OsHle.Svc
             int  ThreadHandle   =  (int)ThreadState.X2;
             long Timeout        = (long)ThreadState.X3;
 
-            HThread Thread = Ns.Os.Handles.GetData<HThread>(ThreadHandle);
+            HThread Thread = Process.HandleTable.GetData<HThread>(ThreadHandle);
 
             Mutex M = new Mutex(Process, MutexAddress, ThreadHandle);
 
diff --git a/Ryujinx.Core/OsHle/Utilities/IdPool.cs b/Ryujinx.Core/OsHle/Utilities/IdPool.cs
deleted file mode 100644
index a7e181fa23..0000000000
--- a/Ryujinx.Core/OsHle/Utilities/IdPool.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System.Collections.Generic;
-
-namespace Ryujinx.Core.OsHle.Utilities
-{
-    class IdPool
-    {
-        private HashSet<int> Ids;
-
-        private int CurrId;
-        private int MinId;
-        private int MaxId;
-
-        public IdPool(int Min, int Max)
-        {
-            Ids = new HashSet<int>();
-
-            CurrId = Min;
-            MinId  = Min;
-            MaxId  = Max;
-        }
-
-        public IdPool() : this(1, int.MaxValue) { }
-
-        public int GenerateId()
-        {
-            lock (Ids)
-            {
-                for (int Cnt = MinId; Cnt < MaxId; Cnt++)
-                {
-                    if (Ids.Add(CurrId))
-                    {
-                        return CurrId;
-                    }
-
-                    if (CurrId++ == MaxId)
-                    {
-                        CurrId = MinId;
-                    }
-                }
-
-                return -1;
-            }
-        }
-
-        public bool DeleteId(int Id)
-        {
-            lock (Ids)
-            {
-                return Ids.Remove(Id);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs
index f7ce109f6f..487f3bdb99 100644
--- a/Ryujinx.Core/Switch.cs
+++ b/Ryujinx.Core/Switch.cs
@@ -1,4 +1,3 @@
-using ChocolArm64.Memory;
 using Ryujinx.Core.Input;
 using Ryujinx.Core.OsHle;
 using Ryujinx.Core.Settings;
@@ -10,8 +9,6 @@ namespace Ryujinx.Core
 {
     public class Switch : IDisposable
     {
-        internal AMemory Memory { get; private set; }
-
         internal NsGpu     Gpu { get; private set; }
         internal Horizon   Os  { get; private set; }
         internal VirtualFs VFs { get; private set; }
@@ -24,13 +21,11 @@ namespace Ryujinx.Core
 
         public Switch(IGalRenderer Renderer)
         {
-            Memory = new AMemory();
-
             Gpu = new NsGpu(Renderer);
 
             VFs = new VirtualFs();
 
-            Hid = new Hid(Memory);
+            Hid = new Hid();
 
             Statistics = new PerformanceStatistics();
 
@@ -42,11 +37,6 @@ namespace Ryujinx.Core
             Settings = new SetSys();
         }
 
-        public void FinalizeAllProcesses()
-        {
-            Os.FinalizeAllProcesses();
-        }
-
         public void LoadCart(string ExeFsDir, string RomFsFile = null)
         {
             Os.LoadCart(ExeFsDir, RomFsFile);
@@ -67,12 +57,11 @@ namespace Ryujinx.Core
             Dispose(true);
         }
 
-        protected virtual void Dispose(bool disposing)
+        protected virtual void Dispose(bool Disposing)
         {
-            if (disposing)
+            if (Disposing)
             {
-                Memory.Dispose();
-
+                Os.Dispose();
                 VFs.Dispose();
             }
         }
diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs
index 83d2c699f8..aa4eac4e14 100644
--- a/Ryujinx.Graphics/Gal/IGalRenderer.cs
+++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Gal
         void RunActions();
 
         void InitializeFrameBuffer();
+        void ResetFrameBuffer();
         void Render();
         void SetWindowSize(int Width, int Height);
         void SetFrameBuffer(
diff --git a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
index 7dc4bffe34..b761811f64 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
@@ -24,6 +24,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
         private byte* FbPtr;
 
+        private object FbPtrLock;
+
         public FrameBuffer(int Width, int Height)
         {
             if (Width < 0)
@@ -36,6 +38,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
                 throw new ArgumentOutOfRangeException(nameof(Height));
             }
 
+            FbPtrLock = new object();
+
             TexWidth  = Width;
             TexHeight = Height;
 
@@ -152,7 +156,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
                 throw new ArgumentOutOfRangeException(nameof(Height));
             }
 
-            FbPtr = Fb;
+            lock (FbPtrLock)
+            {
+                FbPtr = Fb;
+            }
 
             if (Width  != TexWidth ||
                 Height != TexHeight)
@@ -178,17 +185,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             GL.Uniform2(OffsetUniformLocation, Offs);
         }
 
+        public void Reset()
+        {
+            lock (FbPtrLock)
+            {
+                FbPtr = null;
+            }
+        }
+
         public void Render()
         {
-            if (FbPtr == null)
+            lock (FbPtrLock)
             {
-                return;
-            }
+                if (FbPtr == null)
+                {
+                    return;
+                }
 
-            for (int Y = 0; Y < TexHeight; Y++)
-            for (int X = 0; X < TexWidth;  X++)
-            {
-                Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
+                for (int Y = 0; Y < TexHeight; Y++)
+                for (int X = 0; X < TexWidth;  X++)
+                {
+                    Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
+                }
             }
 
             GL.BindTexture(TextureTarget.Texture2D, TexHandle);
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
index bdedfc1a87..002e54dadc 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
@@ -43,6 +43,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             FbRenderer = new FrameBuffer(1280, 720);
         }
 
+        public void ResetFrameBuffer()
+        {
+            FbRenderer.Reset();
+        }
+
         public void QueueAction(Action ActionMthd)
         {
             ActionsQueue.Enqueue(ActionMthd);
diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs
index 0b35a7a6c3..b5bbdbc171 100644
--- a/Ryujinx.Tests/Cpu/CpuTest.cs
+++ b/Ryujinx.Tests/Cpu/CpuTest.cs
@@ -28,7 +28,7 @@ namespace Ryujinx.Tests.Cpu
             ATranslator Translator = new ATranslator();
             Memory = new AMemory();
             Memory.Manager.Map(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute);
-            Thread = new AThread(Translator, Memory, ThreadPriority.Normal, EntryPoint);
+            Thread = new AThread(Translator, Memory, EntryPoint);
         }
 
         [TearDown]