Implement NPDM files parser (#169)
* Implement NPDM files parser (Currently not used in Ryujinx) * Add credits * Add Swap32 * Update Npdm.cs * Update ACI0.cs * Update ACID.cs * Update Npdm.cs * Update EndianSwap.cs * Update ACI0.cs * Update ACID.cs * Update KernelAccessControl.cs * Update NpdmInfo.cs * Update ServiceAccessControl.cs * Update NpdmInfo.cs
This commit is contained in:
parent
3c4dafff3f
commit
4e430760b4
10 changed files with 753 additions and 0 deletions
56
Ryujinx.HLE/Loaders/Npdm/ACI0.cs
Normal file
56
Ryujinx.HLE/Loaders/Npdm/ACI0.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
Ryujinx.HLE/Loaders/Npdm/ACID.cs
Normal file
68
Ryujinx.HLE/Loaders/Npdm/ACID.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs
Normal file
28
Ryujinx.HLE/Loaders/Npdm/FSAccessControl.cs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs
Normal file
37
Ryujinx.HLE/Loaders/Npdm/FSAccessHeader.cs
Normal file
|
@ -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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
208
Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs
Normal file
208
Ryujinx.HLE/Loaders/Npdm/KernelAccessControl.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
Ryujinx.HLE/Loaders/Npdm/Npdm.cs
Normal file
87
Ryujinx.HLE/Loaders/Npdm/Npdm.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
Ryujinx.HLE/Loaders/Npdm/NpdmException.cs
Normal file
9
Ryujinx.HLE/Loaders/Npdm/NpdmException.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
|
{
|
||||||
|
public class InvalidNpdmException : Exception
|
||||||
|
{
|
||||||
|
public InvalidNpdmException(string ExMsg) : base(ExMsg) { }
|
||||||
|
}
|
||||||
|
}
|
215
Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs
Normal file
215
Ryujinx.HLE/Loaders/Npdm/NpdmInfo.cs
Normal file
|
@ -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
|
||||||
|
};
|
||||||
|
}
|
35
Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs
Normal file
35
Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,5 +3,15 @@
|
||||||
static class EndianSwap
|
static class EndianSwap
|
||||||
{
|
{
|
||||||
public static short Swap16(short Value) => (short)(((Value >> 8) & 0xff) | (Value << 8));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue