diff options
Diffstat (limited to 'src/Ryujinx.HLE/Loaders/Npdm')
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs | 53 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Npdm/ACID.cs | 61 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs | 28 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs | 37 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs | 23 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs | 72 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs | 42 |
7 files changed, 316 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs b/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs new file mode 100644 index 00000000..209e79d1 --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Npdm/ACI0.cs @@ -0,0 +1,53 @@ +using Ryujinx.HLE.Exceptions; +using System.IO; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + public class Aci0 + { + private const int Aci0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24; + + public ulong TitleId { get; set; } + + public int FsVersion { get; private set; } + public ulong FsPermissionsBitmask { get; private set; } + + public ServiceAccessControl ServiceAccessControl { get; private set; } + public KernelAccessControl KernelAccessControl { get; private set; } + + public Aci0(Stream stream, int offset) + { + stream.Seek(offset, SeekOrigin.Begin); + + BinaryReader reader = new BinaryReader(stream); + + if (reader.ReadInt32() != Aci0Magic) + { + throw new InvalidNpdmException("ACI0 Stream doesn't contain ACI0 section!"); + } + + stream.Seek(0xc, SeekOrigin.Current); + + TitleId = reader.ReadUInt64(); + + // Reserved. + stream.Seek(8, SeekOrigin.Current); + + 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 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/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs b/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs new file mode 100644 index 00000000..365495c6 --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Npdm/ACID.cs @@ -0,0 +1,61 @@ +using Ryujinx.HLE.Exceptions; +using System.IO; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + public class Acid + { + private const int AcidMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24; + + public byte[] Rsa2048Signature { get; private set; } + public byte[] Rsa2048Modulus { get; private set; } + public int Unknown1 { get; private set; } + public int Flags { get; private set; } + + public long TitleIdRangeMin { get; private set; } + public long TitleIdRangeMax { get; private set; } + + public FsAccessControl FsAccessControl { get; private set; } + public ServiceAccessControl ServiceAccessControl { get; private set; } + public KernelAccessControl KernelAccessControl { get; private set; } + + public Acid(Stream stream, int offset) + { + stream.Seek(offset, SeekOrigin.Begin); + + BinaryReader reader = new BinaryReader(stream); + + Rsa2048Signature = reader.ReadBytes(0x100); + Rsa2048Modulus = reader.ReadBytes(0x100); + + if (reader.ReadInt32() != AcidMagic) + { + throw new InvalidNpdmException("ACID Stream doesn't contain ACID section!"); + } + + // Size field used with the above signature (?). + Unknown1 = reader.ReadInt32(); + + reader.ReadInt32(); + + // Bit0 must be 1 on retail, on devunit 0 is also allowed. Bit1 is unknown. + Flags = reader.ReadInt32(); + + TitleIdRangeMin = reader.ReadInt64(); + TitleIdRangeMax = reader.ReadInt64(); + + 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/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs new file mode 100644 index 00000000..d0f349ea --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessControl.cs @@ -0,0 +1,28 @@ +using System.IO; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + public class FsAccessControl + { + 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 stream, int offset, int size) + { + stream.Seek(offset, SeekOrigin.Begin); + + BinaryReader reader = new BinaryReader(stream); + + Version = reader.ReadInt32(); + PermissionsBitmask = reader.ReadUInt64(); + Unknown1 = reader.ReadInt32(); + Unknown2 = reader.ReadInt32(); + Unknown3 = reader.ReadInt32(); + Unknown4 = reader.ReadInt32(); + } + } +} diff --git a/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs new file mode 100644 index 00000000..564b8dc3 --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Npdm/FsAccessHeader.cs @@ -0,0 +1,37 @@ +using Ryujinx.HLE.Exceptions; +using System; +using System.IO; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + class FsAccessHeader + { + public int Version { get; private set; } + public ulong PermissionsBitmask { get; private set; } + + public FsAccessHeader(Stream stream, int offset, int size) + { + stream.Seek(offset, SeekOrigin.Begin); + + BinaryReader reader = new BinaryReader(stream); + + Version = reader.ReadInt32(); + PermissionsBitmask = reader.ReadUInt64(); + + int dataSize = reader.ReadInt32(); + + if (dataSize != 0x1c) + { + throw new InvalidNpdmException("FsAccessHeader is corrupted!"); + } + + int contentOwnerIdSize = reader.ReadInt32(); + int dataAndContentOwnerIdSize = reader.ReadInt32(); + + if (dataAndContentOwnerIdSize != 0x1c) + { + throw new NotImplementedException("ContentOwnerId section is not implemented!"); + } + } + } +} diff --git a/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs new file mode 100644 index 00000000..39803642 --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs @@ -0,0 +1,23 @@ +using System.IO; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + public class KernelAccessControl + { + public int[] Capabilities { get; private set; } + + public KernelAccessControl(Stream stream, int offset, int size) + { + stream.Seek(offset, SeekOrigin.Begin); + + Capabilities = new int[size / 4]; + + BinaryReader reader = new BinaryReader(stream); + + for (int index = 0; index < Capabilities.Length; index++) + { + Capabilities[index] = reader.ReadInt32(); + } + } + } +} diff --git a/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs new file mode 100644 index 00000000..29a2b0fc --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Npdm/Npdm.cs @@ -0,0 +1,72 @@ +using Ryujinx.HLE.Exceptions; +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 + public class Npdm + { + private const int MetaMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24; + + public byte ProcessFlags { get; private set; } + public bool Is64Bit { get; private set; } + public byte MainThreadPriority { get; private set; } + public byte DefaultCpuId { get; private set; } + public int PersonalMmHeapSize { get; private set; } + public int Version { get; private set; } + public int MainThreadStackSize { get; private set; } + public string TitleName { get; set; } + public byte[] ProductCode { get; private set; } + + public Aci0 Aci0 { get; private set; } + public Acid Acid { get; private set; } + + public Npdm(Stream stream) + { + BinaryReader reader = new BinaryReader(stream); + + if (reader.ReadInt32() != MetaMagic) + { + throw new InvalidNpdmException("NPDM Stream doesn't contain NPDM file!"); + } + + reader.ReadInt64(); + + ProcessFlags = reader.ReadByte(); + + Is64Bit = (ProcessFlags & 1) != 0; + + reader.ReadByte(); + + MainThreadPriority = reader.ReadByte(); + DefaultCpuId = reader.ReadByte(); + + reader.ReadInt32(); + + PersonalMmHeapSize = reader.ReadInt32(); + + Version = reader.ReadInt32(); + + MainThreadStackSize = reader.ReadInt32(); + + byte[] tempTitleName = reader.ReadBytes(0x10); + + TitleName = Encoding.UTF8.GetString(tempTitleName, 0, tempTitleName.Length).Trim('\0'); + + ProductCode = reader.ReadBytes(0x10); + + stream.Seek(0x30, SeekOrigin.Current); + + int aci0Offset = reader.ReadInt32(); + int aci0Size = reader.ReadInt32(); + int acidOffset = reader.ReadInt32(); + int acidSize = reader.ReadInt32(); + + Aci0 = new Aci0(stream, aci0Offset); + Acid = new Acid(stream, acidOffset); + } + } +} diff --git a/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs b/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs new file mode 100644 index 00000000..54012b8a --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Text; + +namespace Ryujinx.HLE.Loaders.Npdm +{ + public class ServiceAccessControl + { + public IReadOnlyDictionary<string, bool> Services { get; private set; } + + public ServiceAccessControl(Stream stream, int offset, int size) + { + stream.Seek(offset, SeekOrigin.Begin); + + BinaryReader reader = new BinaryReader(stream); + + int bytesRead = 0; + + Dictionary<string, bool> services = new Dictionary<string, bool>(); + + while (bytesRead != size) + { + byte controlByte = reader.ReadByte(); + + if (controlByte == 0) + { + break; + } + + int length = (controlByte & 0x07) + 1; + bool registerAllowed = (controlByte & 0x80) != 0; + + services[Encoding.ASCII.GetString(reader.ReadBytes(length))] = registerAllowed; + + bytesRead += length + 1; + } + + Services = new ReadOnlyDictionary<string, bool>(services); + } + } +} |
