Some style fixes on NPDM

This commit is contained in:
gdkchan 2018-08-15 22:48:47 -03:00
commit 4be888c213
16 changed files with 508 additions and 474 deletions

View file

@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Exceptions
{ {
public class InvalidNpdmException : Exception public class InvalidNpdmException : Exception
{ {

View file

@ -1,55 +1,53 @@
using System; using Ryujinx.HLE.Exceptions;
using System.IO; using System.IO;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
class ACI0 class ACI0
{ {
public string TitleId; private const int ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24;
private int FSAccessHeaderOffset; public long TitleId { get; private set; }
private int FSAccessHeaderSize;
private int ServiceAccessControlOffset;
private int ServiceAccessControlSize;
private int KernelAccessControlOffset;
private int KernelAccessControlSize;
public FSAccessHeader FSAccessHeader; public int FsVersion { get; private set; }
public ServiceAccessControl ServiceAccessControl; public ulong FsPermissionsBitmask { get; private set; }
public KernelAccessControl KernelAccessControl;
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) if (Reader.ReadInt32() != ACI0Magic)
{ {
throw new InvalidNpdmException("ACI0 Stream doesn't contain ACI0 section!"); 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); TitleId = Reader.ReadInt64();
Array.Reverse(TempTitleId);
TitleId = BitConverter.ToString(TempTitleId).Replace("-", "");
// Reserved (Not currently used, potentially to be used for lowest title ID in future.) //Reserved.
ACI0Stream.Seek(0x08, SeekOrigin.Current); Stream.Seek(8, SeekOrigin.Current);
FSAccessHeaderOffset = Reader.ReadInt32(); int FSAccessHeaderOffset = Reader.ReadInt32();
FSAccessHeaderSize = Reader.ReadInt32(); int FSAccessHeaderSize = Reader.ReadInt32();
ServiceAccessControlOffset = Reader.ReadInt32(); int ServiceAccessControlOffset = Reader.ReadInt32();
ServiceAccessControlSize = Reader.ReadInt32(); int ServiceAccessControlSize = Reader.ReadInt32();
KernelAccessControlOffset = Reader.ReadInt32(); int KernelAccessControlOffset = Reader.ReadInt32();
KernelAccessControlSize = Reader.ReadInt32(); int KernelAccessControlSize = Reader.ReadInt32();
FSAccessHeader = new FSAccessHeader(ACI0Stream, Offset + FSAccessHeaderOffset, FSAccessHeaderSize); FsAccessHeader FsAccessHeader = new FsAccessHeader(Stream, Offset + FSAccessHeaderOffset, FSAccessHeaderSize);
ServiceAccessControl = new ServiceAccessControl(ACI0Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize);
KernelAccessControl = new KernelAccessControl(ACI0Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize); FsVersion = FsAccessHeader.Version;
FsPermissionsBitmask = FsAccessHeader.PermissionsBitmask;
ServiceAccessControl = new ServiceAccessControl(Stream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize);
KernelAccessControl = new KernelAccessControl(Stream, Offset + KernelAccessControlOffset, KernelAccessControlSize);
} }
} }
} }

View file

@ -1,36 +1,29 @@
using System; using Ryujinx.HLE.Exceptions;
using System.IO; using System.IO;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
class ACID class ACID
{ {
public byte[] RSA2048Signature; private const int ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24;
public byte[] RSA2048Modulus;
public int Unknown1;
public int Flags;
public string TitleIdRangeMin; public byte[] RSA2048Signature { get; private set; }
public string TitleIdRangeMax; public byte[] RSA2048Modulus { get; private set; }
public int Unknown1 { get; private set; }
public int Flags { get; private set; }
private int FSAccessControlOffset; public long TitleIdRangeMin { get; private set; }
private int FSAccessControlSize; public long TitleIdRangeMax { get; private set; }
private int ServiceAccessControlOffset;
private int ServiceAccessControlSize;
private int KernelAccessControlOffset;
private int KernelAccessControlSize;
public FSAccessControl FSAccessControl; public FsAccessControl FsAccessControl { get; private set; }
public ServiceAccessControl ServiceAccessControl; public ServiceAccessControl ServiceAccessControl { get; private set; }
public KernelAccessControl KernelAccessControl; public KernelAccessControl KernelAccessControl { get; private set; }
public const long ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24; public ACID(Stream Stream, int Offset)
public ACID(Stream ACIDStream, 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); RSA2048Signature = Reader.ReadBytes(0x100);
RSA2048Modulus = 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!"); throw new InvalidNpdmException("ACID Stream doesn't contain ACID section!");
} }
Unknown1 = Reader.ReadInt32(); // Size field used with the above signature(?). //Size field used with the above signature (?).
Reader.ReadInt32(); // Padding / Unused Unknown1 = Reader.ReadInt32();
Flags = Reader.ReadInt32(); // Bit0 must be 1 on retail, on devunit 0 is also allowed. Bit1 is unknown.
byte[] TempTitleIdRangeMin = Reader.ReadBytes(8); Reader.ReadInt32();
Array.Reverse(TempTitleIdRangeMin);
TitleIdRangeMin = BitConverter.ToString(TempTitleIdRangeMin).Replace("-", "");
byte[] TempTitleIdRangeMax = Reader.ReadBytes(8); //Bit0 must be 1 on retail, on devunit 0 is also allowed. Bit1 is unknown.
Array.Reverse(TempTitleIdRangeMax); Flags = Reader.ReadInt32();
TitleIdRangeMax = BitConverter.ToString(TempTitleIdRangeMax).Replace("-", "");
FSAccessControlOffset = Reader.ReadInt32(); TitleIdRangeMin = Reader.ReadInt64();
FSAccessControlSize = Reader.ReadInt32(); TitleIdRangeMax = Reader.ReadInt64();
ServiceAccessControlOffset = Reader.ReadInt32();
ServiceAccessControlSize = Reader.ReadInt32();
KernelAccessControlOffset = Reader.ReadInt32();
KernelAccessControlSize = Reader.ReadInt32();
FSAccessControl = new FSAccessControl(ACIDStream, Offset + FSAccessControlOffset, FSAccessControlSize); int FsAccessControlOffset = Reader.ReadInt32();
ServiceAccessControl = new ServiceAccessControl(ACIDStream, Offset + ServiceAccessControlOffset, ServiceAccessControlSize); int FsAccessControlSize = Reader.ReadInt32();
KernelAccessControl = new KernelAccessControl(ACIDStream, Offset + KernelAccessControlOffset, KernelAccessControlSize); 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);
} }
} }
} }

View file

@ -0,0 +1,9 @@
namespace Ryujinx.HLE.Loaders.Npdm
{
enum ApplicationType
{
SystemModule,
Application,
Applet
}
}

View file

@ -2,20 +2,20 @@
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
public class FSAccessControl class FsAccessControl
{ {
public int Version; public int Version { get; private set; }
public ulong PermissionsBitmask; public ulong PermissionsBitmask { get; private set; }
public int Unknown1; public int Unknown1 { get; private set; }
public int Unknown2; public int Unknown2 { get; private set; }
public int Unknown3; public int Unknown3 { get; private set; }
public int Unknown4; 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(); Version = Reader.ReadInt32();
PermissionsBitmask = Reader.ReadUInt64(); PermissionsBitmask = Reader.ReadUInt64();

View file

@ -1,36 +1,37 @@
using System.IO; using System;
using System.IO;
using Ryujinx.HLE.Exceptions;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
public class FSAccessHeader public class FsAccessHeader
{ {
public int Version; public int Version { get; private set; }
public ulong PermissionsBitmask; public ulong PermissionsBitmask { get; private set; }
public int DataSize;
public int ContentOwnerIDSize;
public int DataAndContentOwnerIDSize;
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(); Version = Reader.ReadInt32();
PermissionsBitmask = Reader.ReadUInt64(); 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(); int ContentOwnerIdSize = Reader.ReadInt32();
DataAndContentOwnerIDSize = 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!");
} }
} }
} }

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -1,79 +1,40 @@
using System.Collections.Generic; using Ryujinx.HLE.Exceptions;
using System;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
public class KernelAccessControlIRQ class KernelAccessControl
{ {
public uint IRQ0; public ReadOnlyCollection<KernelAccessControlItem> Items;
public uint IRQ1;
}
public class KernelAccessControlMMIO public KernelAccessControl(Stream Stream, int Offset, int Size)
{ {
public ulong Address; Stream.Seek(Offset, SeekOrigin.Begin);
public ulong Size;
public bool IsRO;
public bool IsNormal;
}
public class KernelAccessControlItems BinaryReader Reader = new BinaryReader(Stream);
{
public bool HasKernelFlags;
public uint LowestThreadPriority;
public uint HighestThreadPriority;
public uint LowestCpuId;
public uint HighestCpuId;
public bool HasSVCFlags; KernelAccessControlItem[] Items = new KernelAccessControlItem[Size / 4];
public int[] SVCsAllowed;
public List<KernelAccessControlMMIO> NormalMMIO; for (int Index = 0; Index < Size / 4; Index++)
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(); uint Descriptor = Reader.ReadUInt32();
if (Descriptor == 0xFFFFFFFF) //Ignore the descriptor //Ignore the descriptor.
if (Descriptor == 0xffffffff)
{ {
continue; continue;
} }
Items[i] = new KernelAccessControlItems(); Items[Index] = new KernelAccessControlItem();
int LowBits = 0; int LowBits = 0;
while ((Descriptor & 1) != 0) while ((Descriptor & 1) != 0)
{ {
Descriptor >>= 1; Descriptor >>= 1;
LowBits++; LowBits++;
} }
@ -81,128 +42,132 @@ namespace Ryujinx.HLE.Loaders.Npdm
switch (LowBits) switch (LowBits)
{ {
case 3: // Kernel flags //Kernel flags.
case 3:
{ {
Items[i].HasKernelFlags = true; Items[Index].HasKernelFlags = true;
Items[i].HighestThreadPriority = Descriptor & 0x3F; Items[Index].HighestThreadPriority = (Descriptor >> 0) & 0x3f;
Items[i].LowestThreadPriority = (Descriptor >> 6) & 0x3F; Items[Index].LowestThreadPriority = (Descriptor >> 6) & 0x3f;
Items[i].LowestCpuId = (Descriptor >> 12) & 0xFF; Items[Index].LowestCpuId = (Descriptor >> 12) & 0xff;
Items[i].HighestCpuId = (Descriptor >> 20) & 0xFF; Items[Index].HighestCpuId = (Descriptor >> 20) & 0xff;
break; 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; int SysCallBase = (int)(Descriptor >> 24) * 0x18;
for (int SysCall = 0; SysCall < 0x18 && SysCallBase + SysCall < 0x80; SysCall++) 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; Descriptor >>= 1;
} }
break; break;
} }
case 6: // Map IO/Normal - Never tested. //Map IO/Normal.
case 6:
{ {
KernelAccessControlMMIO TempNormalMMIO = new KernelAccessControlMMIO ulong Address = (Descriptor & 0xffffff) << 12;
{ bool IsRo = (Descriptor >> 24) != 0;
Address = (Descriptor & 0xFFFFFF) << 12,
IsRO = (Descriptor >> 24) != 0
};
if (i == Size / 4 - 1) if (Index == Size / 4 - 1)
{ {
throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!"); throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!");
} }
Descriptor = Reader.ReadUInt32(); Descriptor = Reader.ReadUInt32();
if ((Descriptor & 0x7F) != 0x3F) if ((Descriptor & 0x7f) != 0x3f)
{ {
throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!"); throw new InvalidNpdmException("Invalid Kernel Access Control Descriptors!");
} }
Descriptor >>= 7; Descriptor >>= 7;
TempNormalMMIO.Size = (Descriptor & 0xFFFFFF) << 12;
TempNormalMMIO.IsNormal = (Descriptor >> 24) != 0;
Items[i].NormalMMIO.Add(TempNormalMMIO); ulong MmioSize = (Descriptor & 0xffffff) << 12;
i++; bool IsNormal = (Descriptor >> 24) != 0;
Items[Index].NormalMmio.Add(new KernelAccessControlMmio(Address, MmioSize, IsRo, IsNormal));
Index++;
break; break;
} }
case 7: // Map Normal Page - Never tested. //Map Normal Page.
case 7:
{ {
KernelAccessControlMMIO TempPageMMIO = new KernelAccessControlMMIO ulong Address = Descriptor << 12;
{
Address = Descriptor << 12,
Size = 0x1000,
IsRO = false,
IsNormal = false
};
Items[i].PageMMIO.Add(TempPageMMIO); Items[Index].PageMmio.Add(new KernelAccessControlMmio(Address, 0x1000, false, false));
break; break;
} }
case 11: // IRQ Pair - Never tested. //IRQ Pair.
case 11:
{ {
KernelAccessControlIRQ TempIRQ = new KernelAccessControlIRQ Items[Index].Irq.Add(new KernelAccessControlIrq(
{ (Descriptor >> 0) & 0x3ff,
IRQ0 = Descriptor & 0x3FF, (Descriptor >> 10) & 0x3ff));
IRQ1 = (Descriptor >> 10) & 0x3FF
};
break; break;
} }
case 13: // App Type //Application Type.
case 13:
{ {
Items[i].HasApplicationType = true; Items[Index].HasApplicationType = true;
Items[i].ApplicationType = (int)Descriptor & 7;
Items[Index].ApplicationType = (int)Descriptor & 7;
break; 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; 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; break;
} }
case 16: // Debug Flags //Debug Flags.
case 16:
{ {
Items[i].HasDebugFlags = true; Items[Index].HasDebugFlags = true;
Items[i].AllowDebug = (Descriptor & 1) != 0; Items[Index].AllowDebug = ((Descriptor >> 0) & 1) != 0;
Items[i].ForceDebug = ((Descriptor >> 1) & 1) != 0; Items[Index].ForceDebug = ((Descriptor >> 1) & 1) != 0;
break; break;
} }
} }
} }
this.Items = Array.AsReadOnly(Items);
} }
} }
} }

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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<KernelAccessControlMmio> NormalMmio { get; set; }
public List<KernelAccessControlMmio> PageMmio { get; set; }
public List<KernelAccessControlIrq> 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; }
}
}

View file

@ -1,3 +1,4 @@
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System.IO; using System.IO;
using System.Text; using System.Text;
@ -9,77 +10,69 @@ namespace Ryujinx.HLE.Loaders.Npdm
//http://switchbrew.org/index.php?title=NPDM //http://switchbrew.org/index.php?title=NPDM
class Npdm class Npdm
{ {
public bool Is64Bits; private const int MetaMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24;
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; public bool Is64Bits { get; private set; }
private int ACI0Size; public int AddressSpaceWidth { get; private set; }
private int ACIDOffset; public byte MainThreadPriority { get; private set; }
private int ACIDSize; 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 ACI0 ACI0 { get; private set; }
public ACID ACID; public ACID ACID { get; private set; }
public const long NpdmMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24; public Npdm(Stream Stream)
public Npdm(Stream NPDMStream)
{ {
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!"); 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 //MmuFlags, bit0: 64-bit instructions, bits1-3: address space width (1=64-bit, 2=32-bit). Needs to be <= 0xF.
byte MmuFlags = Reader.ReadByte(); byte MmuFlags = Reader.ReadByte();
Is64Bits = (MmuFlags & 1) != 0; Is64Bits = (MmuFlags & 1) != 0;
AddressSpaceWidth = (MmuFlags >> 1) & 7; AddressSpaceWidth = (MmuFlags >> 1) & 7;
Reader.ReadByte(); // Padding / Unused Reader.ReadByte();
MainThreadPriority = Reader.ReadByte(); // (0-63) MainThreadPriority = Reader.ReadByte(); //(0-63).
DefaultCpuId = Reader.ReadByte(); 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()); 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()); ProcessCategory = EndianSwap.Swap32(Reader.ReadInt32());
// Main entrypoint stack size //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(); MainEntrypointStackSize = Reader.ReadInt32();
byte[] TempTitleName = Reader.ReadBytes(0x10); byte[] TempTitleName = Reader.ReadBytes(0x10);
TitleName = Encoding.UTF8.GetString(TempTitleName, 0, TempTitleName.Length).Trim('\0'); TitleName = Encoding.UTF8.GetString(TempTitleName, 0, TempTitleName.Length).Trim('\0');
ProductCode = Reader.ReadBytes(0x10); // Unknown value ProductCode = Reader.ReadBytes(0x10);
NPDMStream.Seek(0x30, SeekOrigin.Current); // Skip reserved bytes Stream.Seek(0x30, SeekOrigin.Current);
ACI0Offset = Reader.ReadInt32(); int ACI0Offset = Reader.ReadInt32();
ACI0Size = Reader.ReadInt32(); int ACI0Size = Reader.ReadInt32();
ACIDOffset = Reader.ReadInt32(); int ACIDOffset = Reader.ReadInt32();
ACIDSize = Reader.ReadInt32(); int ACIDSize = Reader.ReadInt32();
ACI0 = new ACI0(NPDMStream, ACI0Offset); ACI0 = new ACI0(Stream, ACI0Offset);
ACID = new ACID(NPDMStream, ACIDOffset); ACID = new ACID(Stream, ACIDOffset);
FSPerms = ACI0.FSAccessHeader.PermissionsBitmask & ACID.FSAccessControl.PermissionsBitmask;
} }
} }
} }

View file

@ -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
};
}

View file

@ -1,34 +1,42 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace Ryujinx.HLE.Loaders.Npdm namespace Ryujinx.HLE.Loaders.Npdm
{ {
public class ServiceAccessControl class ServiceAccessControl
{ {
public List<(string, bool)> Services = new List<(string, bool)>(); public IReadOnlyDictionary<string, bool> 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; int ByteReaded = 0;
Dictionary<string, bool> Services = new Dictionary<string, bool>();
while (ByteReaded != Size) while (ByteReaded != Size)
{ {
byte ControlByte = Reader.ReadByte(); byte ControlByte = Reader.ReadByte();
if (ControlByte == 0x00) break; if (ControlByte == 0)
{
break;
}
int Length = ((ControlByte & 0x07)) + 1; int Length = ((ControlByte & 0x07)) + 1;
bool RegisterAllowed = ((ControlByte & 0x80) != 0); 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; ByteReaded += Length + 1;
} }
this.Services = new ReadOnlyDictionary<string, bool>(Services);
} }
} }
} }

View file

@ -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
}
}