diff --git a/Ryujinx.HLE/Loaders/Npdm/NpdmException.cs b/Ryujinx.HLE/Exceptions/InvalidNpdmException.cs similarity index 77% rename from Ryujinx.HLE/Loaders/Npdm/NpdmException.cs rename to Ryujinx.HLE/Exceptions/InvalidNpdmException.cs index d87a6461da..58d044345e 100644 --- a/Ryujinx.HLE/Loaders/Npdm/NpdmException.cs +++ b/Ryujinx.HLE/Exceptions/InvalidNpdmException.cs @@ -1,9 +1,9 @@ -using System; - -namespace Ryujinx.HLE.Loaders.Npdm -{ - public class InvalidNpdmException : Exception - { - public InvalidNpdmException(string ExMsg) : base(ExMsg) { } - } -} +using System; + +namespace Ryujinx.HLE.Exceptions +{ + public class InvalidNpdmException : Exception + { + public InvalidNpdmException(string ExMsg) : base(ExMsg) { } + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs index 47b30a3c2a..b698d55fc5 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs @@ -1,55 +1,53 @@ -using System; +using Ryujinx.HLE.Exceptions; using System.IO; namespace Ryujinx.HLE.Loaders.Npdm { class ACI0 { - public string TitleId; + private const int ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24; - private int FSAccessHeaderOffset; - private int FSAccessHeaderSize; - private int ServiceAccessControlOffset; - private int ServiceAccessControlSize; - private int KernelAccessControlOffset; - private int KernelAccessControlSize; + public long TitleId { get; private set; } - public FSAccessHeader FSAccessHeader; - public ServiceAccessControl ServiceAccessControl; - public KernelAccessControl KernelAccessControl; + public int FsVersion { get; private set; } + public ulong FsPermissionsBitmask { get; private set; } - public const long ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24; + public ServiceAccessControl ServiceAccessControl { get; private set; } + public KernelAccessControl KernelAccessControl { get; private set; } - public ACI0(Stream ACI0Stream, int Offset) + public ACI0(Stream Stream, int Offset) { - ACI0Stream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(ACI0Stream); + BinaryReader Reader = new BinaryReader(Stream); if (Reader.ReadInt32() != ACI0Magic) { throw new InvalidNpdmException("ACI0 Stream doesn't contain ACI0 section!"); } - ACI0Stream.Seek(0x0C, SeekOrigin.Current); + Stream.Seek(0xc, SeekOrigin.Current); - byte[] TempTitleId = Reader.ReadBytes(8); - Array.Reverse(TempTitleId); - TitleId = BitConverter.ToString(TempTitleId).Replace("-", ""); + TitleId = Reader.ReadInt64(); - // Reserved (Not currently used, potentially to be used for lowest title ID in future.) - ACI0Stream.Seek(0x08, SeekOrigin.Current); + //Reserved. + Stream.Seek(8, SeekOrigin.Current); - FSAccessHeaderOffset = Reader.ReadInt32(); - FSAccessHeaderSize = Reader.ReadInt32(); - ServiceAccessControlOffset = Reader.ReadInt32(); - ServiceAccessControlSize = Reader.ReadInt32(); - KernelAccessControlOffset = Reader.ReadInt32(); - KernelAccessControlSize = Reader.ReadInt32(); + int FSAccessHeaderOffset = Reader.ReadInt32(); + int FSAccessHeaderSize = Reader.ReadInt32(); + int ServiceAccessControlOffset = Reader.ReadInt32(); + int ServiceAccessControlSize = Reader.ReadInt32(); + int KernelAccessControlOffset = Reader.ReadInt32(); + int KernelAccessControlSize = Reader.ReadInt32(); - FSAccessHeader = new FSAccessHeader(ACI0Stream, Offset + FSAccessHeaderOffset, FSAccessHeaderSize); - ServiceAccessControl = new ServiceAccessControl(ACI0Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); - KernelAccessControl = new KernelAccessControl(ACI0Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize); + FsAccessHeader FsAccessHeader = new FsAccessHeader(Stream, Offset + FSAccessHeaderOffset, FSAccessHeaderSize); + + FsVersion = FsAccessHeader.Version; + FsPermissionsBitmask = FsAccessHeader.PermissionsBitmask; + + ServiceAccessControl = new ServiceAccessControl(Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); + + KernelAccessControl = new KernelAccessControl(Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/ACID.cs b/Ryujinx.HLE/Loaders/Npdm/ACID.cs index 09768a9283..7ead32942d 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ACID.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ACID.cs @@ -1,36 +1,29 @@ -using System; +using Ryujinx.HLE.Exceptions; using System.IO; namespace Ryujinx.HLE.Loaders.Npdm { class ACID { - public byte[] RSA2048Signature; - public byte[] RSA2048Modulus; - public int Unknown1; - public int Flags; + private const int ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24; - public string TitleIdRangeMin; - public string TitleIdRangeMax; + public byte[] RSA2048Signature { get; private set; } + public byte[] RSA2048Modulus { get; private set; } + public int Unknown1 { get; private set; } + public int Flags { get; private set; } - private int FSAccessControlOffset; - private int FSAccessControlSize; - private int ServiceAccessControlOffset; - private int ServiceAccessControlSize; - private int KernelAccessControlOffset; - private int KernelAccessControlSize; + public long TitleIdRangeMin { get; private set; } + public long TitleIdRangeMax { get; private set; } - public FSAccessControl FSAccessControl; - public ServiceAccessControl ServiceAccessControl; - public KernelAccessControl KernelAccessControl; + public FsAccessControl FsAccessControl { get; private set; } + public ServiceAccessControl ServiceAccessControl { get; private set; } + public KernelAccessControl KernelAccessControl { get; private set; } - public const long ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24; - - public ACID(Stream ACIDStream, int Offset) + public ACID(Stream Stream, int Offset) { - ACIDStream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(ACIDStream); + BinaryReader Reader = new BinaryReader(Stream); RSA2048Signature = Reader.ReadBytes(0x100); RSA2048Modulus = Reader.ReadBytes(0x100); @@ -40,28 +33,29 @@ namespace Ryujinx.HLE.Loaders.Npdm 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. + //Size field used with the above signature (?). + Unknown1 = Reader.ReadInt32(); - byte[] TempTitleIdRangeMin = Reader.ReadBytes(8); - Array.Reverse(TempTitleIdRangeMin); - TitleIdRangeMin = BitConverter.ToString(TempTitleIdRangeMin).Replace("-", ""); + Reader.ReadInt32(); - byte[] TempTitleIdRangeMax = Reader.ReadBytes(8); - Array.Reverse(TempTitleIdRangeMax); - TitleIdRangeMax = BitConverter.ToString(TempTitleIdRangeMax).Replace("-", ""); + //Bit0 must be 1 on retail, on devunit 0 is also allowed. Bit1 is unknown. + Flags = Reader.ReadInt32(); - FSAccessControlOffset = Reader.ReadInt32(); - FSAccessControlSize = Reader.ReadInt32(); - ServiceAccessControlOffset = Reader.ReadInt32(); - ServiceAccessControlSize = Reader.ReadInt32(); - KernelAccessControlOffset = Reader.ReadInt32(); - KernelAccessControlSize = Reader.ReadInt32(); + TitleIdRangeMin = Reader.ReadInt64(); + TitleIdRangeMax = Reader.ReadInt64(); - FSAccessControl = new FSAccessControl(ACIDStream, Offset + FSAccessControlOffset, FSAccessControlSize); - ServiceAccessControl = new ServiceAccessControl(ACIDStream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); - KernelAccessControl = new KernelAccessControl(ACIDStream, Offset + KernelAccessControlOffset, KernelAccessControlSize); + int FsAccessControlOffset = Reader.ReadInt32(); + int FsAccessControlSize = Reader.ReadInt32(); + int ServiceAccessControlOffset = Reader.ReadInt32(); + int ServiceAccessControlSize = Reader.ReadInt32(); + int KernelAccessControlOffset = Reader.ReadInt32(); + int KernelAccessControlSize = Reader.ReadInt32(); + + FsAccessControl = new FsAccessControl(Stream, Offset + FsAccessControlOffset, FsAccessControlSize); + + ServiceAccessControl = new ServiceAccessControl(Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); + + KernelAccessControl = new KernelAccessControl(Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/ApplicationType.cs b/Ryujinx.HLE/Loaders/Npdm/ApplicationType.cs new file mode 100644 index 0000000000..ad27903280 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/ApplicationType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + enum ApplicationType + { + SystemModule, + Application, + Applet + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs index ca8eac2e76..7f108256a3 100644 --- a/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs +++ b/Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs @@ -2,20 +2,20 @@ namespace Ryujinx.HLE.Loaders.Npdm { - public class FSAccessControl + class FsAccessControl { - public int Version; - public ulong PermissionsBitmask; - public int Unknown1; - public int Unknown2; - public int Unknown3; - public int Unknown4; + public int Version { get; private set; } + public ulong PermissionsBitmask { get; private set; } + public int Unknown1 { get; private set; } + public int Unknown2 { get; private set; } + public int Unknown3 { get; private set; } + public int Unknown4 { get; private set; } - public FSAccessControl(Stream FSAccessHeaderStream, int Offset, int Size) + public FsAccessControl(Stream Stream, int Offset, int Size) { - FSAccessHeaderStream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(FSAccessHeaderStream); + BinaryReader Reader = new BinaryReader(Stream); Version = Reader.ReadInt32(); PermissionsBitmask = Reader.ReadUInt64(); diff --git a/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs b/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs index 0ba3af7341..c6d2cf348a 100644 --- a/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs +++ b/Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs @@ -1,36 +1,37 @@ -using System.IO; +using System; +using System.IO; + +using Ryujinx.HLE.Exceptions; namespace Ryujinx.HLE.Loaders.Npdm { - public class FSAccessHeader + public class FsAccessHeader { - public int Version; - public ulong PermissionsBitmask; - public int DataSize; - public int ContentOwnerIDSize; - public int DataAndContentOwnerIDSize; + public int Version { get; private set; } + public ulong PermissionsBitmask { get; private set; } - public FSAccessHeader(Stream FSAccessHeaderStream, int Offset, int Size) + public FsAccessHeader(Stream Stream, int Offset, int Size) { - FSAccessHeaderStream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(FSAccessHeaderStream); + BinaryReader Reader = new BinaryReader(Stream); Version = Reader.ReadInt32(); PermissionsBitmask = Reader.ReadUInt64(); - DataSize = Reader.ReadInt32(); - if (DataSize != 0x1C) + int DataSize = Reader.ReadInt32(); + + if (DataSize != 0x1c) { - throw new InvalidNpdmException("FSAccessHeader is corrupted!"); + throw new InvalidNpdmException("FsAccessHeader is corrupted!"); } - ContentOwnerIDSize = Reader.ReadInt32(); - DataAndContentOwnerIDSize = Reader.ReadInt32(); + int ContentOwnerIdSize = Reader.ReadInt32(); + int DataAndContentOwnerIdSize = Reader.ReadInt32(); - if (DataAndContentOwnerIDSize != 0x1C) + if (DataAndContentOwnerIdSize != 0x1c) { - throw new InvalidNpdmException("ContentOwnerID section is not implemented!"); + throw new NotImplementedException("ContentOwnerId section is not implemented!"); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/FsPermissionBool.cs b/Ryujinx.HLE/Loaders/Npdm/FsPermissionBool.cs new file mode 100644 index 0000000000..571b7b5a80 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/FsPermissionBool.cs @@ -0,0 +1,33 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + 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 + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/FsPermissionRw.cs b/Ryujinx.HLE/Loaders/Npdm/FsPermissionRw.cs new file mode 100644 index 0000000000..ca21279b5e --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/FsPermissionRw.cs @@ -0,0 +1,45 @@ +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 + } +} diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs index 46fad63e8e..0b45ebfbbd 100644 --- a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs +++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs @@ -1,79 +1,40 @@ -using System.Collections.Generic; +using Ryujinx.HLE.Exceptions; +using System; +using System.Collections.ObjectModel; using System.IO; namespace Ryujinx.HLE.Loaders.Npdm { - public class KernelAccessControlIRQ + class KernelAccessControl { - public uint IRQ0; - public uint IRQ1; - } + public ReadOnlyCollection Items; - 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 NormalMMIO; - public List PageMMIO; - public List 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) + public KernelAccessControl(Stream Stream, int Offset, int Size) { - FSAccessControlsStream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(FSAccessControlsStream); + BinaryReader Reader = new BinaryReader(Stream); - Items = new KernelAccessControlItems[Size / 4]; + KernelAccessControlItem[] Items = new KernelAccessControlItem[Size / 4]; - for (int i = 0; i < Size / 4; i++) + for (int Index = 0; Index < Size / 4; Index++) { uint Descriptor = Reader.ReadUInt32(); - if (Descriptor == 0xFFFFFFFF) //Ignore the descriptor + //Ignore the descriptor. + if (Descriptor == 0xffffffff) { continue; } - Items[i] = new KernelAccessControlItems(); + Items[Index] = new KernelAccessControlItem(); int LowBits = 0; while ((Descriptor & 1) != 0) { Descriptor >>= 1; + LowBits++; } @@ -81,128 +42,132 @@ namespace Ryujinx.HLE.Loaders.Npdm switch (LowBits) { - case 3: // Kernel flags + //Kernel flags. + case 3: { - Items[i].HasKernelFlags = true; + Items[Index].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; + Items[Index].HighestThreadPriority = (Descriptor >> 0) & 0x3f; + Items[Index].LowestThreadPriority = (Descriptor >> 6) & 0x3f; + Items[Index].LowestCpuId = (Descriptor >> 12) & 0xff; + Items[Index].HighestCpuId = (Descriptor >> 20) & 0xff; break; } - case 4: // Syscall mask + //Syscall mask. + case 4: { - Items[i].HasSVCFlags = true; + Items[Index].HasSvcFlags = true; - Items[i].SVCsAllowed = new int[0x80]; + Items[Index].AllowedSvcs = new bool[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; + Items[Index].AllowedSvcs[SysCallBase + SysCall] = (Descriptor & 1) != 0; + Descriptor >>= 1; } break; } - case 6: // Map IO/Normal - Never tested. + //Map IO/Normal. + case 6: { - KernelAccessControlMMIO TempNormalMMIO = new KernelAccessControlMMIO - { - Address = (Descriptor & 0xFFFFFF) << 12, - IsRO = (Descriptor >> 24) != 0 - }; + ulong Address = (Descriptor & 0xffffff) << 12; + bool IsRo = (Descriptor >> 24) != 0; - if (i == Size / 4 - 1) + if (Index == Size / 4 - 1) { throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!"); } Descriptor = Reader.ReadUInt32(); - if ((Descriptor & 0x7F) != 0x3F) + 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++; + ulong MmioSize = (Descriptor & 0xffffff) << 12; + bool IsNormal = (Descriptor >> 24) != 0; + + Items[Index].NormalMmio.Add(new KernelAccessControlMmio(Address, MmioSize, IsRo, IsNormal)); + + Index++; break; } - case 7: // Map Normal Page - Never tested. + //Map Normal Page. + case 7: { - KernelAccessControlMMIO TempPageMMIO = new KernelAccessControlMMIO - { - Address = Descriptor << 12, - Size = 0x1000, - IsRO = false, - IsNormal = false - }; + ulong Address = Descriptor << 12; - Items[i].PageMMIO.Add(TempPageMMIO); + Items[Index].PageMmio.Add(new KernelAccessControlMmio(Address, 0x1000, false, false)); break; } - case 11: // IRQ Pair - Never tested. + //IRQ Pair. + case 11: { - KernelAccessControlIRQ TempIRQ = new KernelAccessControlIRQ - { - IRQ0 = Descriptor & 0x3FF, - IRQ1 = (Descriptor >> 10) & 0x3FF - }; + Items[Index].Irq.Add(new KernelAccessControlIrq( + (Descriptor >> 0) & 0x3ff, + (Descriptor >> 10) & 0x3ff)); break; } - case 13: // App Type + //Application Type. + case 13: { - Items[i].HasApplicationType = true; - Items[i].ApplicationType = (int)Descriptor & 7; + Items[Index].HasApplicationType = true; + + Items[Index].ApplicationType = (int)Descriptor & 7; break; } - case 14: // Kernel Release Version + //Kernel Release Version. + case 14: { - Items[i].HasKernelVersion = true; + Items[Index].HasKernelVersion = true; - Items[i].KernelVersionRelease = (int)Descriptor; + Items[Index].KernelVersionRelease = (int)Descriptor; break; } - case 15: // Handle Table Size + //Handle Table Size. + case 15: { - Items[i].HasHandleTableSize = true; + Items[Index].HasHandleTableSize = true; - Items[i].HandleTableSize = (int)Descriptor; + Items[Index].HandleTableSize = (int)Descriptor; break; } - case 16: // Debug Flags + //Debug Flags. + case 16: { - Items[i].HasDebugFlags = true; + Items[Index].HasDebugFlags = true; - Items[i].AllowDebug = (Descriptor & 1) != 0; - Items[i].ForceDebug = ((Descriptor >> 1) & 1) != 0; + Items[Index].AllowDebug = ((Descriptor >> 0) & 1) != 0; + Items[Index].ForceDebug = ((Descriptor >> 1) & 1) != 0; break; } } } + + this.Items = Array.AsReadOnly(Items); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlIrq.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlIrq.cs new file mode 100644 index 0000000000..636713317a --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlIrq.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + struct KernelAccessControlIrq + { + public uint Irq0 { get; private set; } + public uint Irq1 { get; private set; } + + public KernelAccessControlIrq(uint Irq0, uint Irq1) + { + this.Irq0 = Irq0; + this.Irq1 = Irq1; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlMmio.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlMmio.cs new file mode 100644 index 0000000000..bb164c8eba --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessControlMmio.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + struct KernelAccessControlMmio + { + public ulong Address; + public ulong Size; + public bool IsRo; + public bool IsNormal; + + public KernelAccessControlMmio( + ulong Address, + ulong Size, + bool IsRo, + bool IsNormal) + { + this.Address = Address; + this.Size = Size; + this.IsRo = IsRo; + this.IsNormal = IsNormal; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/Npdm/KernelAccessItem.cs b/Ryujinx.HLE/Loaders/Npdm/KernelAccessItem.cs new file mode 100644 index 0000000000..42015c3ea2 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/KernelAccessItem.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + struct KernelAccessControlItem + { + public bool HasKernelFlags { get; set; } + public uint LowestThreadPriority { get; set; } + public uint HighestThreadPriority { get; set; } + public uint LowestCpuId { get; set; } + public uint HighestCpuId { get; set; } + + public bool HasSvcFlags { get; set; } + public bool[] AllowedSvcs { get; set; } + + public List NormalMmio { get; set; } + public List PageMmio { get; set; } + public List Irq { get; set; } + + public bool HasApplicationType { get; set; } + public int ApplicationType { get; set; } + + public bool HasKernelVersion { get; set; } + public int KernelVersionRelease { get; set; } + + public bool HasHandleTableSize { get; set; } + public int HandleTableSize { get; set; } + + public bool HasDebugFlags { get; set; } + public bool AllowDebug { get; set; } + public bool ForceDebug { get; set; } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs index 14151b4c00..8aacfd99ef 100644 --- a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs +++ b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs @@ -1,3 +1,4 @@ +using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Utilities; using System.IO; using System.Text; @@ -9,77 +10,69 @@ namespace Ryujinx.HLE.Loaders.Npdm //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 const int MetaMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24; - private int ACI0Offset; - private int ACI0Size; - private int ACIDOffset; - private int ACIDSize; + public bool Is64Bits { get; private set; } + public int AddressSpaceWidth { get; private set; } + public byte MainThreadPriority { get; private set; } + public byte DefaultCpuId { get; private set; } + public int SystemResourceSize { get; private set; } + public int ProcessCategory { get; private set; } + public int MainEntrypointStackSize { get; private set; } + public string TitleName { get; private set; } + public byte[] ProductCode { get; private set; } - public ACI0 ACI0; - public ACID ACID; + public ACI0 ACI0 { get; private set; } + public ACID ACID { get; private set; } - public const long NpdmMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24; - - public Npdm(Stream NPDMStream) + public Npdm(Stream Stream) { - BinaryReader Reader = new BinaryReader(NPDMStream); + BinaryReader Reader = new BinaryReader(Stream); - if (Reader.ReadInt32() != NpdmMagic) + if (Reader.ReadInt32() != MetaMagic) { throw new InvalidNpdmException("NPDM Stream doesn't contain NPDM file!"); } - Reader.ReadInt64(); // Padding / Unused + Reader.ReadInt64(); + + //MmuFlags, bit0: 64-bit instructions, bits1-3: address space width (1=64-bit, 2=32-bit). Needs to be <= 0xF. + byte MmuFlags = Reader.ReadByte(); - // 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 + Reader.ReadByte(); - MainThreadPriority = Reader.ReadByte(); // (0-63) + MainThreadPriority = Reader.ReadByte(); //(0-63). DefaultCpuId = Reader.ReadByte(); - Reader.ReadInt32(); // Padding / Unused + Reader.ReadInt32(); - // System resource size (max size as of 5.x: 534773760). Unknown usage. + //System resource size (max size as of 5.x: 534773760). SystemResourceSize = EndianSwap.Swap32(Reader.ReadInt32()); - // ProcessCategory (0: regular title, 1: kernel built-in). Should be 0 here. + //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 ?) + //Main entrypoint stack size. MainEntrypointStackSize = Reader.ReadInt32(); byte[] TempTitleName = Reader.ReadBytes(0x10); - TitleName = Encoding.UTF8.GetString(TempTitleName, 0, TempTitleName.Length).Trim('\0'); - ProductCode = Reader.ReadBytes(0x10); // Unknown value + TitleName = Encoding.UTF8.GetString(TempTitleName, 0, TempTitleName.Length).Trim('\0'); - NPDMStream.Seek(0x30, SeekOrigin.Current); // Skip reserved bytes + ProductCode = Reader.ReadBytes(0x10); - ACI0Offset = Reader.ReadInt32(); - ACI0Size = Reader.ReadInt32(); - ACIDOffset = Reader.ReadInt32(); - ACIDSize = Reader.ReadInt32(); + Stream.Seek(0x30, SeekOrigin.Current); - ACI0 = new ACI0(NPDMStream, ACI0Offset); - ACID = new ACID(NPDMStream, ACIDOffset); + int ACI0Offset = Reader.ReadInt32(); + int ACI0Size = Reader.ReadInt32(); + int ACIDOffset = Reader.ReadInt32(); + int ACIDSize = Reader.ReadInt32(); - FSPerms = ACI0.FSAccessHeader.PermissionsBitmask & ACID.FSAccessControl.PermissionsBitmask; + ACI0 = new ACI0(Stream, ACI0Offset); + ACID = new ACID(Stream, ACIDOffset); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs b/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs deleted file mode 100644 index 72e6b3e254..0000000000 --- a/Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs +++ /dev/null @@ -1,215 +0,0 @@ -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 index ddd7d7ed2b..910eacb38b 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs @@ -1,34 +1,42 @@ using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Text; namespace Ryujinx.HLE.Loaders.Npdm { - public class ServiceAccessControl + class ServiceAccessControl { - public List<(string, bool)> Services = new List<(string, bool)>(); + public IReadOnlyDictionary Services { get; private set; } - public ServiceAccessControl(Stream ServiceAccessControlStream, int Offset, int Size) + public ServiceAccessControl(Stream Stream, int Offset, int Size) { - ServiceAccessControlStream.Seek(Offset, SeekOrigin.Begin); + Stream.Seek(Offset, SeekOrigin.Begin); - BinaryReader Reader = new BinaryReader(ServiceAccessControlStream); + BinaryReader Reader = new BinaryReader(Stream); int ByteReaded = 0; + Dictionary Services = new Dictionary(); + while (ByteReaded != Size) { byte ControlByte = Reader.ReadByte(); - if (ControlByte == 0x00) break; + if (ControlByte == 0) + { + break; + } - int Length = ((ControlByte & 0x07)) + 1; - bool RegisterAllowed = ((ControlByte & 0x80) != 0); + int Length = ((ControlByte & 0x07)) + 1; + bool RegisterAllowed = ((ControlByte & 0x80) != 0); - Services.Add((Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed)); + Services.Add(Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed); ByteReaded += Length + 1; } + + this.Services = new ReadOnlyDictionary(Services); } } } diff --git a/Ryujinx.HLE/Loaders/Npdm/SvcName.cs b/Ryujinx.HLE/Loaders/Npdm/SvcName.cs new file mode 100644 index 0000000000..e519e05ec0 --- /dev/null +++ b/Ryujinx.HLE/Loaders/Npdm/SvcName.cs @@ -0,0 +1,134 @@ +namespace Ryujinx.HLE.Loaders.Npdm +{ + enum SvcName + { + Reserved0, + SetHeapSize, + SetMemoryPermission, + SetMemoryAttribute, + MapMemory, + UnmapMemory, + QueryMemory, + ExitProcess, + CreateThread, + StartThread, + ExitThread, + SleepThread, + GetThreadPriority, + SetThreadPriority, + GetThreadCoreMask, + SetThreadCoreMask, + GetCurrentProcessorNumber, + SignalEvent, + ClearEvent, + MapSharedMemory, + UnmapSharedMemory, + CreateTransferMemory, + CloseHandle, + ResetSignal, + WaitSynchronization, + CancelSynchronization, + ArbitrateLock, + ArbitrateUnlock, + WaitProcessWideKeyAtomic, + SignalProcessWideKey, + GetSystemTick, + ConnectToNamedPort, + SendSyncRequestLight, + SendSyncRequest, + SendSyncRequestWithUserBuffer, + SendAsyncRequestWithUserBuffer, + GetProcessId, + GetThreadId, + Break, + OutputDebugString, + ReturnFromException, + GetInfo, + FlushEntireDataCache, + FlushDataCache, + MapPhysicalMemory, + UnmapPhysicalMemory, + GetFutureThreadInfo, + GetLastThreadInfo, + GetResourceLimitLimitValue, + GetResourceLimitCurrentValue, + SetThreadActivity, + GetThreadContext3, + WaitForAddress, + SignalToAddress, + Reserved1, + Reserved2, + Reserved3, + Reserved4, + Reserved5, + Reserved6, + DumpInfo, + DumpInfoNew, + Reserved7, + Reserved8, + CreateSession, + AcceptSession, + ReplyAndReceiveLight, + ReplyAndReceive, + ReplyAndReceiveWithUserBuffer, + CreateEvent, + Reserved9, + Reserved10, + MapPhysicalMemoryUnsafe, + UnmapPhysicalMemoryUnsafe, + SetUnsafeLimit, + CreateCodeMemory, + ControlCodeMemory, + SleepSystem, + ReadWriteRegister, + SetProcessActivity, + CreateSharedMemory, + MapTransferMemory, + UnmapTransferMemory, + CreateInterruptEvent, + QueryPhysicalAddress, + QueryIoMapping, + CreateDeviceAddressSpace, + AttachDeviceAddressSpace, + DetachDeviceAddressSpace, + MapDeviceAddressSpaceByForce, + MapDeviceAddressSpaceAligned, + MapDeviceAddressSpace, + UnmapDeviceAddressSpace, + InvalidateProcessDataCache, + StoreProcessDataCache, + FlushProcessDataCache, + DebugActiveProcess, + BreakDebugProcess, + TerminateDebugProcess, + GetDebugEvent, + ContinueDebugEvent, + GetProcessList, + GetThreadList, + GetDebugThreadContext, + SetDebugThreadContext, + QueryDebugProcessMemory, + ReadDebugProcessMemory, + WriteDebugProcessMemory, + SetHardwareBreakPoint, + GetDebugThreadParam, + Reserved11, + GetSystemInfo, + CreatePort, + ManageNamedPort, + ConnectToPort, + SetProcessMemoryPermission, + MapProcessMemory, + UnmapProcessMemory, + QueryProcessMemory, + MapProcessCodeMemory, + UnmapProcessCodeMemory, + CreateProcess, + StartProcess, + TerminateProcess, + GetProcessInfo, + CreateResourceLimit, + SetResourceLimitLimitValue, + CallSecureMonitor + } +}