diff --git a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs
new file mode 100644
index 0000000000..1f1b810ef6
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs
@@ -0,0 +1,56 @@
+using Ryujinx.HLE.OsHle.Utilities;
+using System;
+using System.IO;
+
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    class ACI0
+    {
+        public string TitleId;
+
+        private int FSAccessHeaderOffset;
+        private int FSAccessHeaderSize;
+        private int ServiceAccessControlOffset;
+        private int ServiceAccessControlSize;
+        private int KernelAccessControlOffset;
+        private int KernelAccessControlSize;
+
+        public FSAccessHeader       FSAccessHeader;
+        public ServiceAccessControl ServiceAccessControl;
+        public KernelAccessControl  KernelAccessControl;
+
+        public const long ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24;
+        
+        public ACI0(Stream ACI0Stream, int Offset)
+        {
+            ACI0Stream.Seek(Offset, SeekOrigin.Begin);
+
+            BinaryReader Reader = new BinaryReader(ACI0Stream);
+
+            if (Reader.ReadInt32() != ACI0Magic)
+            {
+                throw new InvalidNpdmException("ACI0 Stream doesn't contain ACI0 section!");
+            }
+
+            ACI0Stream.Seek(0x0C, SeekOrigin.Current);
+
+            byte[] TempTitleId = Reader.ReadBytes(8);
+            Array.Reverse(TempTitleId);
+            TitleId = BitConverter.ToString(TempTitleId).Replace("-", "");
+
+            // Reserved (Not currently used, potentially to be used for lowest title ID in future.)
+            ACI0Stream.Seek(0x08, SeekOrigin.Current);
+
+            FSAccessHeaderOffset       = Reader.ReadInt32();
+            FSAccessHeaderSize         = Reader.ReadInt32();
+            ServiceAccessControlOffset = Reader.ReadInt32();
+            ServiceAccessControlSize   = Reader.ReadInt32();
+            KernelAccessControlOffset  = Reader.ReadInt32();
+            KernelAccessControlSize    = Reader.ReadInt32();
+
+            FSAccessHeader       = new FSAccessHeader(ACI0Stream, Offset + FSAccessHeaderOffset, FSAccessHeaderSize);
+            ServiceAccessControl = new ServiceAccessControl(ACI0Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize);
+            KernelAccessControl  = new KernelAccessControl(ACI0Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize);
+        }
+    }
+}
diff --git a/Ryujinx.HLE/Loaders/Npdm/ACID.cs b/Ryujinx.HLE/Loaders/Npdm/ACID.cs
new file mode 100644
index 0000000000..d0f0acdd5e
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/ACID.cs
@@ -0,0 +1,68 @@
+using Ryujinx.HLE.OsHle.Utilities;
+using System;
+using System.IO;
+
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    class ACID
+    {
+        public byte[] RSA2048Signature;
+        public byte[] RSA2048Modulus;
+        public int    Unknown1;
+        public int    Flags;
+
+        public string TitleIdRangeMin;
+        public string TitleIdRangeMax;
+
+        private int FSAccessControlOffset;
+        private int FSAccessControlSize;
+        private int ServiceAccessControlOffset;
+        private int ServiceAccessControlSize;
+        private int KernelAccessControlOffset;
+        private int KernelAccessControlSize;
+
+        public FSAccessControl      FSAccessControl;
+        public ServiceAccessControl ServiceAccessControl;
+        public KernelAccessControl  KernelAccessControl;
+        
+        public const long ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24;
+
+        public ACID(Stream ACIDStream, int Offset)
+        {
+            ACIDStream.Seek(Offset, SeekOrigin.Begin);
+
+            BinaryReader Reader = new BinaryReader(ACIDStream);
+
+            RSA2048Signature = Reader.ReadBytes(0x100);
+            RSA2048Modulus   = Reader.ReadBytes(0x100);
+
+            if (Reader.ReadInt32() != ACIDMagic)
+            {
+                throw new InvalidNpdmException("ACID Stream doesn't contain ACID section!");
+            }
+
+            Unknown1 = Reader.ReadInt32(); // Size field used with the above signature(?).
+            Reader.ReadInt32(); // Padding / Unused
+            Flags = Reader.ReadInt32(); // Bit0 must be 1 on retail, on devunit 0 is also allowed. Bit1 is unknown.
+
+            byte[] TempTitleIdRangeMin = Reader.ReadBytes(8);
+            Array.Reverse(TempTitleIdRangeMin);
+            TitleIdRangeMin = BitConverter.ToString(TempTitleIdRangeMin).Replace("-", "");
+
+            byte[] TempTitleIdRangeMax = Reader.ReadBytes(8);
+            Array.Reverse(TempTitleIdRangeMax);
+            TitleIdRangeMax = BitConverter.ToString(TempTitleIdRangeMax).Replace("-", "");
+
+            FSAccessControlOffset      = Reader.ReadInt32();
+            FSAccessControlSize        = Reader.ReadInt32();
+            ServiceAccessControlOffset = Reader.ReadInt32();
+            ServiceAccessControlSize   = Reader.ReadInt32();
+            KernelAccessControlOffset  = Reader.ReadInt32();
+            KernelAccessControlSize    = Reader.ReadInt32();
+
+            FSAccessControl      = new FSAccessControl(ACIDStream, Offset + FSAccessControlOffset, FSAccessControlSize);
+            ServiceAccessControl = new ServiceAccessControl(ACIDStream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize);
+            KernelAccessControl  = new KernelAccessControl(ACIDStream, Offset + KernelAccessControlOffset, KernelAccessControlSize);
+        }
+    }
+}
diff --git a/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs
new file mode 100644
index 0000000000..ca8eac2e76
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs
@@ -0,0 +1,28 @@
+using System.IO;
+
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    public class FSAccessControl
+    {
+        public int   Version;
+        public ulong PermissionsBitmask;
+        public int   Unknown1;
+        public int   Unknown2;
+        public int   Unknown3;
+        public int   Unknown4;
+
+        public FSAccessControl(Stream FSAccessHeaderStream, int Offset, int Size)
+        {
+            FSAccessHeaderStream.Seek(Offset, SeekOrigin.Begin);
+
+            BinaryReader Reader = new BinaryReader(FSAccessHeaderStream);
+
+            Version            = Reader.ReadInt32();
+            PermissionsBitmask = Reader.ReadUInt64();
+            Unknown1           = Reader.ReadInt32();
+            Unknown2           = Reader.ReadInt32();
+            Unknown3           = Reader.ReadInt32();
+            Unknown4           = Reader.ReadInt32();
+        }
+    }
+}
diff --git a/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs b/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs
new file mode 100644
index 0000000000..0ba3af7341
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs
@@ -0,0 +1,37 @@
+using System.IO;
+
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    public class FSAccessHeader
+    {
+        public int   Version;
+        public ulong PermissionsBitmask;
+        public int   DataSize;
+        public int   ContentOwnerIDSize;
+        public int   DataAndContentOwnerIDSize;
+
+        public FSAccessHeader(Stream FSAccessHeaderStream, int Offset, int Size)
+        {
+            FSAccessHeaderStream.Seek(Offset, SeekOrigin.Begin);
+
+            BinaryReader Reader = new BinaryReader(FSAccessHeaderStream);
+
+            Version            = Reader.ReadInt32();
+            PermissionsBitmask = Reader.ReadUInt64();
+            DataSize           = Reader.ReadInt32();
+
+            if (DataSize != 0x1C)
+            {
+                throw new InvalidNpdmException("FSAccessHeader is corrupted!");
+            }
+
+            ContentOwnerIDSize        = Reader.ReadInt32();
+            DataAndContentOwnerIDSize = Reader.ReadInt32();
+
+            if (DataAndContentOwnerIDSize != 0x1C)
+            {
+                throw new InvalidNpdmException("ContentOwnerID section is not implemented!");
+            }
+        }
+    }
+}
diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs
new file mode 100644
index 0000000000..46fad63e8e
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs
@@ -0,0 +1,208 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    public class KernelAccessControlIRQ
+    {
+        public uint IRQ0;
+        public uint IRQ1;
+    }
+
+    public class KernelAccessControlMMIO
+    {
+        public ulong Address;
+        public ulong Size;
+        public bool  IsRO;
+        public bool  IsNormal;
+    }
+
+    public class KernelAccessControlItems
+    {
+        public bool  HasKernelFlags;
+        public uint  LowestThreadPriority;
+        public uint  HighestThreadPriority;
+        public uint  LowestCpuId;
+        public uint  HighestCpuId;
+
+        public bool  HasSVCFlags;
+        public int[] SVCsAllowed;
+
+        public List<KernelAccessControlMMIO> NormalMMIO;
+        public List<KernelAccessControlMMIO> PageMMIO;
+        public List<KernelAccessControlIRQ>  IRQ;
+
+        public bool HasApplicationType;
+        public int  ApplicationType;
+
+        public bool HasKernelVersion;
+        public int  KernelVersionRelease;
+
+        public bool HasHandleTableSize;
+        public int  HandleTableSize;
+
+        public bool HasDebugFlags;
+        public bool AllowDebug;
+        public bool ForceDebug;
+    }
+
+    public class KernelAccessControl
+    {
+        public KernelAccessControlItems[] Items;
+
+        public KernelAccessControl(Stream FSAccessControlsStream, int Offset, int Size)
+        {
+            FSAccessControlsStream.Seek(Offset, SeekOrigin.Begin);
+
+            BinaryReader Reader = new BinaryReader(FSAccessControlsStream);
+
+            Items = new KernelAccessControlItems[Size / 4];
+
+            for (int i = 0; i < Size / 4; i++)
+            {
+                uint Descriptor = Reader.ReadUInt32();
+
+                if (Descriptor == 0xFFFFFFFF) //Ignore the descriptor
+                {
+                    continue;
+                }
+
+                Items[i] = new KernelAccessControlItems();
+
+                int LowBits = 0;
+
+                while ((Descriptor & 1) != 0)
+                {
+                    Descriptor >>= 1;
+                    LowBits++;
+                }
+
+                Descriptor >>= 1;
+
+                switch (LowBits)
+                {
+                    case 3: // Kernel flags
+                    {
+                        Items[i].HasKernelFlags        = true;
+
+                        Items[i].HighestThreadPriority = Descriptor & 0x3F;
+                        Items[i].LowestThreadPriority  = (Descriptor >> 6) & 0x3F;
+                        Items[i].LowestCpuId           = (Descriptor >> 12) & 0xFF;
+                        Items[i].HighestCpuId          = (Descriptor >> 20) & 0xFF;
+
+                        break;
+                    }
+
+                    case 4: // Syscall mask
+                    {
+                        Items[i].HasSVCFlags = true;
+
+                        Items[i].SVCsAllowed = new int[0x80];
+
+                        int SysCallBase = (int)(Descriptor >> 24) * 0x18;
+
+                        for (int SysCall = 0; SysCall < 0x18 && SysCallBase + SysCall < 0x80; SysCall++)
+                        {
+                            Items[i].SVCsAllowed[SysCallBase + SysCall] = (int)Descriptor & 1;
+                            Descriptor >>= 1;
+                        }
+
+                        break;
+                    }
+
+                    case 6: // Map IO/Normal - Never tested.
+                    {
+                        KernelAccessControlMMIO TempNormalMMIO = new KernelAccessControlMMIO
+                        {
+                            Address = (Descriptor & 0xFFFFFF) << 12,
+                            IsRO    = (Descriptor >> 24) != 0
+                        };
+
+                        if (i == Size / 4 - 1)
+                        {
+                            throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!");
+                        }
+
+                        Descriptor = Reader.ReadUInt32();
+
+                        if ((Descriptor & 0x7F) != 0x3F)
+                        {
+                            throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!");
+                        }
+
+                        Descriptor >>= 7;
+                        TempNormalMMIO.Size     = (Descriptor & 0xFFFFFF) << 12;
+                        TempNormalMMIO.IsNormal = (Descriptor >> 24) != 0;
+
+                        Items[i].NormalMMIO.Add(TempNormalMMIO);
+                        i++;
+
+                        break;
+                    }
+
+                    case 7: // Map Normal Page - Never tested.
+                    {
+                        KernelAccessControlMMIO TempPageMMIO = new KernelAccessControlMMIO
+                        {
+                            Address  = Descriptor << 12,
+                            Size     = 0x1000,
+                            IsRO     = false,
+                            IsNormal = false
+                        };
+
+                        Items[i].PageMMIO.Add(TempPageMMIO);
+
+                        break;
+                    }
+
+                    case 11: // IRQ Pair - Never tested.
+                    {
+                        KernelAccessControlIRQ TempIRQ = new KernelAccessControlIRQ
+                        {
+                            IRQ0 = Descriptor & 0x3FF,
+                            IRQ1 = (Descriptor >> 10) & 0x3FF
+                        };
+
+                        break;
+                    }
+
+                    case 13: // App Type
+                    {
+                        Items[i].HasApplicationType = true;
+                        Items[i].ApplicationType    = (int)Descriptor & 7;
+
+                        break;
+                    }
+
+                    case 14: // Kernel Release Version
+                    {
+                        Items[i].HasKernelVersion     = true;
+
+                        Items[i].KernelVersionRelease = (int)Descriptor;
+
+                        break;
+                    }
+
+                    case 15: // Handle Table Size
+                    {
+                        Items[i].HasHandleTableSize = true;
+
+                        Items[i].HandleTableSize    = (int)Descriptor;
+
+                        break;
+                    }
+
+                    case 16: // Debug Flags
+                    {
+                        Items[i].HasDebugFlags = true;
+
+                        Items[i].AllowDebug    = (Descriptor & 1) != 0;
+                        Items[i].ForceDebug    = ((Descriptor >> 1) & 1) != 0;
+
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs
new file mode 100644
index 0000000000..d255e668cc
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs
@@ -0,0 +1,87 @@
+using Ryujinx.HLE.OsHle.Utilities;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    //https://github.com/SciresM/hactool/blob/master/npdm.c
+    //https://github.com/SciresM/hactool/blob/master/npdm.h
+    //http://switchbrew.org/index.php?title=NPDM
+    class Npdm
+    {
+        public bool   Is64Bits;
+        public int    AddressSpaceWidth;
+        public byte   MainThreadPriority;
+        public byte   DefaultCpuId;
+        public int    SystemResourceSize;
+        public int    ProcessCategory;
+        public int    MainEntrypointStackSize;
+        public string TitleName;
+        public byte[] ProductCode;
+        public ulong  FSPerms;
+
+        private int ACI0Offset;
+        private int ACI0Size;
+        private int ACIDOffset;
+        private int ACIDSize;
+
+        public ACI0 ACI0;
+        public ACID ACID;
+        
+        public const long NpdmMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24;
+
+        public Npdm(Stream NPDMStream)
+        {
+            BinaryReader Reader = new BinaryReader(NPDMStream);
+
+            if (Reader.ReadInt32() != NpdmMagic)
+            {
+                throw new InvalidNpdmException("NPDM Stream doesn't contain NPDM file!");
+            }
+
+            Reader.ReadInt64(); // Padding / Unused
+
+            // MmuFlags, bit0: 64-bit instructions, bits1-3: address space width (1=64-bit, 2=32-bit). Needs to be <= 0xF
+            byte MmuFlags     = Reader.ReadByte();
+            Is64Bits          = (MmuFlags & 1) != 0;
+            AddressSpaceWidth = (MmuFlags >> 1) & 7;
+
+            Reader.ReadByte(); // Padding / Unused
+
+            MainThreadPriority = Reader.ReadByte(); // (0-63)
+            DefaultCpuId       = Reader.ReadByte();
+
+            Reader.ReadInt32(); // Padding / Unused
+
+            // System resource size (max size as of 5.x: 534773760). Unknown usage.
+            SystemResourceSize = EndianSwap.Swap32(Reader.ReadInt32());
+
+            // ProcessCategory (0: regular title, 1: kernel built-in). Should be 0 here.
+            ProcessCategory = EndianSwap.Swap32(Reader.ReadInt32());
+
+            // Main entrypoint stack size 
+            // (Should(?) be page-aligned. In non-nspwn scenarios, values of 0 can also rarely break in Horizon.
+            // This might be something auto-adapting or a security feature of some sort ?)
+            MainEntrypointStackSize = Reader.ReadInt32();
+
+            byte[] TempTitleName = Reader.ReadBytes(0x10);
+            TitleName            = Encoding.UTF8.GetString(TempTitleName, 0, TempTitleName.Length).Trim('\0');
+
+            ProductCode = Reader.ReadBytes(0x10); // Unknown value
+
+            NPDMStream.Seek(0x30, SeekOrigin.Current); // Skip reserved bytes
+
+            ACI0Offset = Reader.ReadInt32();
+            ACI0Size   = Reader.ReadInt32();
+            ACIDOffset = Reader.ReadInt32();
+            ACIDSize   = Reader.ReadInt32();
+
+            ACI0       = new ACI0(NPDMStream, ACI0Offset);
+            ACID       = new ACID(NPDMStream, ACIDOffset);
+
+            FSPerms    = ACI0.FSAccessHeader.PermissionsBitmask & ACID.FSAccessControl.PermissionsBitmask;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/Loaders/Npdm/NpdmException.cs b/Ryujinx.HLE/Loaders/Npdm/NpdmException.cs
new file mode 100644
index 0000000000..d87a6461da
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/NpdmException.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    public class InvalidNpdmException : Exception
+    {
+        public InvalidNpdmException(string ExMsg) : base(ExMsg) { }
+    }
+}
diff --git a/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs b/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs
new file mode 100644
index 0000000000..72e6b3e254
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs
@@ -0,0 +1,215 @@
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    enum FSPermissionRW : ulong
+    {
+        MountContentType2     = 0x8000000000000801,
+        MountContentType5     = 0x8000000000000801,
+        MountContentType3     = 0x8000000000000801,
+        MountContentType4     = 0x8000000000000801,
+        MountContentType6     = 0x8000000000000801,
+        MountContentType7     = 0x8000000000000801,
+        Unknown0x6            = 0x8000000000000000,
+        ContentStorageAccess  = 0x8000000000000800,
+        ImageDirectoryAccess  = 0x8000000000001000,
+        MountBisType28        = 0x8000000000000084,
+        MountBisType29        = 0x8000000000000080,
+        MountBisType30        = 0x8000000000008080,
+        MountBisType31        = 0x8000000000008080,
+        Unknown0xD            = 0x8000000000000080,
+        SdCardAccess          = 0xC000000000200000,
+        GameCardUser          = 0x8000000000000010,
+        SaveDataAccess0       = 0x8000000000040020,
+        SystemSaveDataAccess0 = 0x8000000000000028,
+        SaveDataAccess1       = 0x8000000000000020,
+        SystemSaveDataAccess1 = 0x8000000000000020,
+        BisPartition0         = 0x8000000000010082,
+        BisPartition10        = 0x8000000000010080,
+        BisPartition20        = 0x8000000000010080,
+        BisPartition21        = 0x8000000000010080,
+        BisPartition22        = 0x8000000000010080,
+        BisPartition23        = 0x8000000000010080,
+        BisPartition24        = 0x8000000000010080,
+        BisPartition25        = 0x8000000000010080,
+        BisPartition26        = 0x8000000000000080,
+        BisPartition27        = 0x8000000000000084,
+        BisPartition28        = 0x8000000000000084,
+        BisPartition29        = 0x8000000000000080,
+        BisPartition30        = 0x8000000000000080,
+        BisPartition31        = 0x8000000000000080,
+        BisPartition32        = 0x8000000000000080,
+        Unknown0x23           = 0xC000000000200000,
+        GameCard_System       = 0x8000000000000100,
+        MountContent_System   = 0x8000000000100008,
+        HostAccess            = 0xC000000000400000
+    };
+
+    enum FSPermissionBool : ulong
+    {
+        BisCache                  = 0x8000000000000080,
+        EraseMmc                  = 0x8000000000000080,
+        GameCardCertificate       = 0x8000000000000010,
+        GameCardIdSet             = 0x8000000000000010,
+        GameCardDriver            = 0x8000000000000200,
+        GameCardAsic              = 0x8000000000000200,
+        SaveDataCreate            = 0x8000000000002020,
+        SaveDataDelete0           = 0x8000000000000060,
+        SystemSaveDataCreate0     = 0x8000000000000028,
+        SystemSaveDataCreate1     = 0x8000000000000020,
+        SaveDataDelete1           = 0x8000000000004028,
+        SaveDataIterators0        = 0x8000000000000060,
+        SaveDataIterators1        = 0x8000000000004020,
+        SaveThumbnails            = 0x8000000000020000,
+        PosixTime                 = 0x8000000000000400,
+        SaveDataExtraData         = 0x8000000000004060,
+        GlobalMode                = 0x8000000000080000,
+        SpeedEmulation            = 0x8000000000080000,
+        NULL                      = 0,
+        PaddingFiles              = 0xC000000000800000,
+        SaveData_Debug            = 0xC000000001000000,
+        SaveData_SystemManagement = 0xC000000002000000,
+        Unknown0x16               = 0x8000000004000000,
+        Unknown0x17               = 0x8000000008000000,
+        Unknown0x18               = 0x8000000010000000,
+        Unknown0x19               = 0x8000000000000800,
+        Unknown0x1A               = 0x8000000000004020
+    }
+
+    enum NpdmApplicationType
+    {
+        SystemModule,
+        Application,
+        Applet
+    }
+
+    enum SvcName
+    {
+        svcUnknown0,
+        svcSetHeapSize,
+        svcSetMemoryPermission,
+        svcSetMemoryAttribute,
+        svcMapMemory,
+        svcUnmapMemory,
+        svcQueryMemory,
+        svcExitProcess,
+        svcCreateThread,
+        svcStartThread,
+        svcExitThread,
+        svcSleepThread,
+        svcGetThreadPriority,
+        svcSetThreadPriority,
+        svcGetThreadCoreMask,
+        svcSetThreadCoreMask,
+        svcGetCurrentProcessorNumber,
+        svcSignalEvent,
+        svcClearEvent,
+        svcMapSharedMemory,
+        svcUnmapSharedMemory,
+        svcCreateTransferMemory,
+        svcCloseHandle,
+        svcResetSignal,
+        svcWaitSynchronization,
+        svcCancelSynchronization,
+        svcArbitrateLock,
+        svcArbitrateUnlock,
+        svcWaitProcessWideKeyAtomic,
+        svcSignalProcessWideKey,
+        svcGetSystemTick,
+        svcConnectToNamedPort,
+        svcSendSyncRequestLight,
+        svcSendSyncRequest,
+        svcSendSyncRequestWithUserBuffer,
+        svcSendAsyncRequestWithUserBuffer,
+        svcGetProcessId,
+        svcGetThreadId,
+        svcBreak,
+        svcOutputDebugString,
+        svcReturnFromException,
+        svcGetInfo,
+        svcFlushEntireDataCache,
+        svcFlushDataCache,
+        svcMapPhysicalMemory,
+        svcUnmapPhysicalMemory,
+        svcGetFutureThreadInfo,
+        svcGetLastThreadInfo,
+        svcGetResourceLimitLimitValue,
+        svcGetResourceLimitCurrentValue,
+        svcSetThreadActivity,
+        svcGetThreadContext3,
+        svcWaitForAddress,
+        svcSignalToAddress,
+        svcUnknown1,
+        svcUnknown2,
+        svcUnknown3,
+        svcUnknown4,
+        svcUnknown5,
+        svcUnknown6,
+        svcDumpInfo,
+        svcDumpInfoNew,
+        svcUnknown7,
+        svcUnknown8,
+        svcCreateSession,
+        svcAcceptSession,
+        svcReplyAndReceiveLight,
+        svcReplyAndReceive,
+        svcReplyAndReceiveWithUserBuffer,
+        svcCreateEvent,
+        svcUnknown9,
+        svcUnknown10,
+        svcMapPhysicalMemoryUnsafe,
+        svcUnmapPhysicalMemoryUnsafe,
+        svcSetUnsafeLimit,
+        svcCreateCodeMemory,
+        svcControlCodeMemory,
+        svcSleepSystem,
+        svcReadWriteRegister,
+        svcSetProcessActivity,
+        svcCreateSharedMemory,
+        svcMapTransferMemory,
+        svcUnmapTransferMemory,
+        svcCreateInterruptEvent,
+        svcQueryPhysicalAddress,
+        svcQueryIoMapping,
+        svcCreateDeviceAddressSpace,
+        svcAttachDeviceAddressSpace,
+        svcDetachDeviceAddressSpace,
+        svcMapDeviceAddressSpaceByForce,
+        svcMapDeviceAddressSpaceAligned,
+        svcMapDeviceAddressSpace,
+        svcUnmapDeviceAddressSpace,
+        svcInvalidateProcessDataCache,
+        svcStoreProcessDataCache,
+        svcFlushProcessDataCache,
+        svcDebugActiveProcess,
+        svcBreakDebugProcess,
+        svcTerminateDebugProcess,
+        svcGetDebugEvent,
+        svcContinueDebugEvent,
+        svcGetProcessList,
+        svcGetThreadList,
+        svcGetDebugThreadContext,
+        svcSetDebugThreadContext,
+        svcQueryDebugProcessMemory,
+        svcReadDebugProcessMemory,
+        svcWriteDebugProcessMemory,
+        svcSetHardwareBreakPoint,
+        svcGetDebugThreadParam,
+        svcUnknown11,
+        svcGetSystemInfo,
+        svcCreatePort,
+        svcManageNamedPort,
+        svcConnectToPort,
+        svcSetProcessMemoryPermission,
+        svcMapProcessMemory,
+        svcUnmapProcessMemory,
+        svcQueryProcessMemory,
+        svcMapProcessCodeMemory,
+        svcUnmapProcessCodeMemory,
+        svcCreateProcess,
+        svcStartProcess,
+        svcTerminateProcess,
+        svcGetProcessInfo,
+        svcCreateResourceLimit,
+        svcSetResourceLimitLimitValue,
+        svcCallSecureMonitor
+    };
+}
diff --git a/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs
new file mode 100644
index 0000000000..fd33841a3d
--- /dev/null
+++ b/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Ryujinx.HLE.Loaders.Npdm
+{
+    public class ServiceAccessControl
+    {
+        public List<(string, bool)> Services = new List<(string, bool)>();
+
+        public ServiceAccessControl(Stream ServiceAccessControlStream, int Offset, int Size)
+        {
+            ServiceAccessControlStream.Seek(Offset, SeekOrigin.Begin);
+
+            BinaryReader Reader = new BinaryReader(ServiceAccessControlStream);
+
+            int ByteReaded = 0;
+
+            while (ByteReaded != Size)
+            {
+                byte ControlByte = Reader.ReadByte();
+
+                if (ControlByte == 0x00) break;
+
+                int Length             = ((ControlByte & 0x07)) + 1;
+                bool RegisterAllowed   = ((ControlByte & 0x80) != 0);
+                
+                Services.Add((Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed));
+
+                ByteReaded += Length + 1;
+            }
+        }
+    }
+}
diff --git a/Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs b/Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs
index 93fd38c8f2..46a2edcb6c 100644
--- a/Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs
+++ b/Ryujinx.HLE/OsHle/Utilities/EndianSwap.cs
@@ -3,5 +3,15 @@
     static class EndianSwap
     {
         public static short Swap16(short Value) => (short)(((Value >> 8) & 0xff) | (Value << 8));
+        
+        public static int Swap32(int Value)
+        {
+            uint UintVal = (uint)Value;
+
+            return (int)(((UintVal >> 24) & 0x000000ff) |
+                         ((UintVal >>  8) & 0x0000ff00) |
+                         ((UintVal <<  8) & 0x00ff0000) |
+                         ((UintVal << 24) & 0xff000000));
+        }
     }
 }