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