mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-12-28 19:36:03 +00:00
f82d7a3db4
* Rewrote mutex handling throughout the code to use a small, macro-based scoped lock implementation. * Removed extern variables from common.h - launch path management is now completely handled in utils.c. * Updated NpdmSystemCallId_Count to reflect changes introduced in 12.0.0. * Added NcaMainSignatureKeyGeneration enum. * NCA main signature moduli are now retrieved from FS .rodata at runtime. * Simplified lock management in usb.c by using a single global mutex with scoped locks instead of three different r/w locks. * Updated FatFs to R0.14b. * Enabled 64-bit LBA support in FatFs to potentially support custom eMMC replacements / resized USER partitions in the future. * Updated LZ4 to v1.9.3. * Fixed typos. * USB gamecard dumper PoC now only dumps the Initial Data area. * Updated to-do list.
649 lines
34 KiB
C
649 lines
34 KiB
C
/*
|
|
* npdm.h
|
|
*
|
|
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
|
*
|
|
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
|
*
|
|
* nxdumptool is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* nxdumptool is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifndef __NPDM_H__
|
|
#define __NPDM_H__
|
|
|
|
#include "pfs.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define NPDM_META_MAGIC 0x4D455441 /* "META". */
|
|
#define NPDM_ACID_MAGIC 0x41434944 /* "ACID". */
|
|
#define NPDM_ACI0_MAGIC 0x41434930 /* "ACI0". */
|
|
|
|
#define NPDM_MAIN_THREAD_MAX_PRIORITY 0x3F
|
|
#define NPDM_MAIN_THREAD_MAX_CORE_NUMBER 3
|
|
#define NPDM_SYSTEM_RESOURCE_MAX_SIZE 0x1FE00000
|
|
#define NPDM_MAIN_THREAD_STACK_SIZE_ALIGNMENT 0x1000
|
|
|
|
typedef enum {
|
|
NpdmProcessAddressSpace_AddressSpace32Bit = 0,
|
|
NpdmProcessAddressSpace_AddressSpace64BitOld = 1,
|
|
NpdmProcessAddressSpace_AddressSpace32BitNoReserved = 2,
|
|
NpdmProcessAddressSpace_AddressSpace64Bit = 3
|
|
} NpdmProcessAddressSpace;
|
|
|
|
typedef struct {
|
|
u8 is_64bit_instruction : 1;
|
|
u8 process_address_space : 3; ///< NpdmProcessAddressSpace.
|
|
u8 optimize_memory_allocation : 1;
|
|
u8 disable_device_address_space_merge : 1;
|
|
u8 reserved : 2;
|
|
} NpdmMetaFlags;
|
|
|
|
NXDT_ASSERT(NpdmMetaFlags, 0x1);
|
|
|
|
/// This is the start of every NPDM file.
|
|
/// This is followed by ACID and ACI0 sections, both with variable offsets and sizes.
|
|
typedef struct {
|
|
u32 magic; ///< "NPDM".
|
|
u8 acid_signature_key_generation;
|
|
u8 reserved_1[0x7];
|
|
NpdmMetaFlags flags;
|
|
u8 reserved_2;
|
|
u8 main_thread_priority; ///< Must not exceed NPDM_MAIN_THREAD_MAX_PRIORITY.
|
|
u8 main_thread_core_number; ///< Must not exceed NPDM_MAIN_THREAD_MAX_CORE_NUMBER.
|
|
u8 reserved_3[0x4];
|
|
u32 system_resource_size; ///< Must not exceed NPDM_SYSTEM_RESOURCE_MAX_SIZE.
|
|
VersionType1 version;
|
|
u32 main_thread_stack_size; ///< Must be aligned to NPDM_MAIN_THREAD_STACK_SIZE_ALIGNMENT.
|
|
char name[0x10]; ///< Usually set to "Application".
|
|
char product_code[0x10]; ///< Usually zeroed out.
|
|
u8 reserved_4[0x30];
|
|
u32 aci_offset; ///< Offset value relative to the start of this header.
|
|
u32 aci_size;
|
|
u32 acid_offset; ///< Offset value relative to the start of this header.
|
|
u32 acid_size;
|
|
} NpdmMetaHeader;
|
|
|
|
NXDT_ASSERT(NpdmMetaHeader, 0x80);
|
|
|
|
typedef enum {
|
|
NpdmMemoryRegion_Application = 0,
|
|
NpdmMemoryRegion_Applet = 1,
|
|
NpdmMemoryRegion_SystemSecure = 2,
|
|
NpdmMemoryRegion_SystemNonSecure = 3,
|
|
|
|
/// Old.
|
|
NpdmMemoryRegion_NonSecure = NpdmMemoryRegion_Application,
|
|
NpdmMemoryRegion_Secure = NpdmMemoryRegion_Applet
|
|
} NpdmMemoryRegion;
|
|
|
|
typedef struct {
|
|
u32 production : 1;
|
|
u32 unqualified_approval : 1;
|
|
u32 memory_region : 2; ///< NpdmMemoryRegion.
|
|
u32 reserved : 28;
|
|
} NpdmAcidFlags;
|
|
|
|
NXDT_ASSERT(NpdmAcidFlags, 0x4);
|
|
|
|
/// This is the start of an ACID section.
|
|
/// This is followed by FsAccessControl, SrvAccessControl and KernelCapability descriptors, each one aligned to a 0x10 byte boundary using zero padding (if needed).
|
|
typedef struct {
|
|
u8 signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over the rest of the ACID section, using the value from the 'size' member.
|
|
u8 public_key[0x100]; ///< RSA public key used to verify the ACID signature from the Program NCA header.
|
|
u32 magic; ///< "ACID".
|
|
u32 size; ///< Must be equal to ACID section size from the META header minus 0x100 (ACID signature size).
|
|
u8 reserved_1[0x4];
|
|
NpdmAcidFlags flags;
|
|
u64 program_id_min;
|
|
u64 program_id_max;
|
|
u32 fs_access_control_offset; ///< Offset value relative to the start of this header.
|
|
u32 fs_access_control_size;
|
|
u32 srv_access_control_offset; ///< Offset value relative to the start of this header.
|
|
u32 srv_access_control_size;
|
|
u32 kernel_capability_offset; ///< Offset value relative to the start of this header.
|
|
u32 kernel_capability_size;
|
|
u8 reserved_2[0x8];
|
|
} NpdmAcidHeader;
|
|
|
|
NXDT_ASSERT(NpdmAcidHeader, 0x240);
|
|
|
|
/// This is the start of an ACI0 section.
|
|
/// This is followed by a FsAccessControl data block, as well as SrvAccessControl and KernelCapability descriptors, each one aligned to a 0x10 byte boundary using zero padding (if needed).
|
|
typedef struct {
|
|
u32 magic;
|
|
u8 reserved_1[0xC];
|
|
u64 program_id;
|
|
u8 reserved_2[0x8];
|
|
u32 fs_access_control_offset; ///< Offset value relative to the start of this header.
|
|
u32 fs_access_control_size;
|
|
u32 srv_access_control_offset; ///< Offset value relative to the start of this header.
|
|
u32 srv_access_control_size;
|
|
u32 kernel_capability_offset; ///< Offset value relative to the start of this header.
|
|
u32 kernel_capability_size;
|
|
u8 reserved_3[0x8];
|
|
} NpdmAciHeader;
|
|
|
|
NXDT_ASSERT(NpdmAciHeader, 0x40);
|
|
|
|
typedef enum {
|
|
NpdmFsAccessControlFlags_ApplicationInfo = BIT_LONG(0),
|
|
NpdmFsAccessControlFlags_BootModeControl = BIT_LONG(1),
|
|
NpdmFsAccessControlFlags_Calibration = BIT_LONG(2),
|
|
NpdmFsAccessControlFlags_SystemSaveData = BIT_LONG(3),
|
|
NpdmFsAccessControlFlags_GameCard = BIT_LONG(4),
|
|
NpdmFsAccessControlFlags_SaveDataBackUp = BIT_LONG(5),
|
|
NpdmFsAccessControlFlags_SaveDataManagement = BIT_LONG(6),
|
|
NpdmFsAccessControlFlags_BisAllRaw = BIT_LONG(7),
|
|
NpdmFsAccessControlFlags_GameCardRaw = BIT_LONG(8),
|
|
NpdmFsAccessControlFlags_GameCardPrivate = BIT_LONG(9),
|
|
NpdmFsAccessControlFlags_SetTime = BIT_LONG(10),
|
|
NpdmFsAccessControlFlags_ContentManager = BIT_LONG(11),
|
|
NpdmFsAccessControlFlags_ImageManager = BIT_LONG(12),
|
|
NpdmFsAccessControlFlags_CreateSaveData = BIT_LONG(13),
|
|
NpdmFsAccessControlFlags_SystemSaveDataManagement = BIT_LONG(14),
|
|
NpdmFsAccessControlFlags_BisFileSystem = BIT_LONG(15),
|
|
NpdmFsAccessControlFlags_SystemUpdate = BIT_LONG(16),
|
|
NpdmFsAccessControlFlags_SaveDataMeta = BIT_LONG(17),
|
|
NpdmFsAccessControlFlags_DeviceSaveData = BIT_LONG(18),
|
|
NpdmFsAccessControlFlags_SettingsControl = BIT_LONG(19),
|
|
NpdmFsAccessControlFlags_SystemData = BIT_LONG(20),
|
|
NpdmFsAccessControlFlags_SdCard = BIT_LONG(21),
|
|
NpdmFsAccessControlFlags_Host = BIT_LONG(22),
|
|
NpdmFsAccessControlFlags_FillBis = BIT_LONG(23),
|
|
NpdmFsAccessControlFlags_CorruptSaveData = BIT_LONG(24),
|
|
NpdmFsAccessControlFlags_SaveDataForDebug = BIT_LONG(25),
|
|
NpdmFsAccessControlFlags_FormatSdCard = BIT_LONG(26),
|
|
NpdmFsAccessControlFlags_GetRightsId = BIT_LONG(27),
|
|
NpdmFsAccessControlFlags_RegisterExternalKey = BIT_LONG(28),
|
|
NpdmFsAccessControlFlags_RegisterUpdatePartition = BIT_LONG(29),
|
|
NpdmFsAccessControlFlags_SaveDataTransfer = BIT_LONG(30),
|
|
NpdmFsAccessControlFlags_DeviceDetection = BIT_LONG(31),
|
|
NpdmFsAccessControlFlags_AccessFailureResolution = BIT_LONG(32),
|
|
NpdmFsAccessControlFlags_SaveDataTransferVersion2 = BIT_LONG(33),
|
|
NpdmFsAccessControlFlags_RegisterProgramIndexMapInfo = BIT_LONG(34),
|
|
NpdmFsAccessControlFlags_CreateOwnSaveData = BIT_LONG(35),
|
|
NpdmFsAccessControlFlags_MoveCacheStorage = BIT_LONG(36),
|
|
NpdmFsAccessControlFlags_Debug = BIT_LONG(62),
|
|
NpdmFsAccessControlFlags_FullPermission = BIT_LONG(63)
|
|
} NpdmFsAccessControlFlags;
|
|
|
|
/// FsAccessControl descriptor. Part of the ACID section body.
|
|
/// This is followed by:
|
|
/// * 'content_owner_id_count' content owner IDs.
|
|
/// * 'save_data_owner_id_count' save data owner IDs.
|
|
#pragma pack(push, 1)
|
|
typedef struct {
|
|
u8 version; ///< Always non-zero. Usually set to 1.
|
|
u8 content_owner_id_count;
|
|
u8 save_data_owner_id_count;
|
|
u8 reserved;
|
|
u64 flags;
|
|
u64 content_owner_id_min;
|
|
u64 content_owner_id_max;
|
|
u64 save_data_owner_id_min;
|
|
u64 save_data_owner_id_max;
|
|
} NpdmFsAccessControlDescriptor;
|
|
#pragma pack(pop)
|
|
|
|
NXDT_ASSERT(NpdmFsAccessControlDescriptor, 0x2C);
|
|
|
|
/// FsAccessControl data. Part of the ACI0 section body.
|
|
/// This is followed by:
|
|
/// * A NpdmFsAccessControlDataContentOwnerBlock if 'content_owner_info_size' is greater than zero.
|
|
/// * A NpdmFsAccessControlDataSaveDataOwnerBlock if 'save_data_owner_info_size' is greater than zero.
|
|
/// * If available, this block is padded to a 0x4-byte boundary and followed by 'save_data_owner_id_count' save data owner IDs.
|
|
#pragma pack(push, 1)
|
|
typedef struct {
|
|
u8 version;
|
|
u8 reserved_1[0x3];
|
|
u64 flags;
|
|
u32 content_owner_info_offset; ///< Relative to the start of this block. Only valid if 'content_owner_info_size' is greater than 0.
|
|
u32 content_owner_info_size;
|
|
u32 save_data_owner_info_offset; ///< Relative to the start of this block. Only valid if 'save_data_owner_info_size' is greater than 0.
|
|
u32 save_data_owner_info_size;
|
|
} NpdmFsAccessControlData;
|
|
#pragma pack(pop)
|
|
|
|
NXDT_ASSERT(NpdmFsAccessControlData, 0x1C);
|
|
|
|
/// Placed after NpdmFsAccessControlData if its 'content_owner_info_size' member is greater than zero.
|
|
#pragma pack(push, 1)
|
|
typedef struct {
|
|
u32 content_owner_id_count;
|
|
u64 content_owner_id[]; ///< 'content_owner_id_count' content owned IDs.
|
|
} NpdmFsAccessControlDataContentOwnerBlock;
|
|
#pragma pack(pop)
|
|
|
|
NXDT_ASSERT(NpdmFsAccessControlDataContentOwnerBlock, 0x4);
|
|
|
|
typedef enum {
|
|
NpdmAccessibility_Read = BIT(0),
|
|
NpdmAccessibility_Write = BIT(1)
|
|
} NpdmAccessibility;
|
|
|
|
/// Placed after NpdmFsAccessControlData / NpdmFsAccessControlDataContentOwnerBlock if the 'content_owner_info_size' member from NpdmFsAccessControlData is greater than zero.
|
|
/// If available, this block is padded to a 0x4-byte boundary and followed by 'save_data_owner_id_count' save data owner IDs.
|
|
typedef struct {
|
|
u32 save_data_owner_id_count;
|
|
u8 accessibility[]; ///< 'save_data_owner_id_count' NpdmAccessibility fields.
|
|
} NpdmFsAccessControlDataSaveDataOwnerBlock;
|
|
|
|
NXDT_ASSERT(NpdmFsAccessControlDataSaveDataOwnerBlock, 0x4);
|
|
|
|
/// SrvAccessControl descriptor. Part of the ACID and ACI0 section bodies.
|
|
/// This descriptor is composed of a variable number of NpdmSrvAccessControlDescriptorEntry elements, each one with a variable size.
|
|
/// Since the total number of services isn't stored anywhere, this descriptor must be parsed until its total size is reached.
|
|
typedef struct {
|
|
u8 name_length : 3; ///< Service name length minus 1.
|
|
u8 reserved : 4;
|
|
u8 is_server : 1; ///< Indicates if the service is allowed to be registered.
|
|
char name[]; ///< Service name, stored without a NULL terminator. Supports the "*" wildcard character.
|
|
} NpdmSrvAccessControlDescriptorEntry;
|
|
|
|
NXDT_ASSERT(NpdmSrvAccessControlDescriptorEntry, 0x1);
|
|
|
|
typedef enum {
|
|
NpdmKernelCapabilityEntryNumber_ThreadInfo = 3,
|
|
NpdmKernelCapabilityEntryNumber_EnableSystemCalls = 4,
|
|
NpdmKernelCapabilityEntryNumber_MemoryMap = 6,
|
|
NpdmKernelCapabilityEntryNumber_IoMemoryMap = 7,
|
|
NpdmKernelCapabilityEntryNumber_MemoryRegionMap = 10,
|
|
NpdmKernelCapabilityEntryNumber_EnableInterrupts = 11,
|
|
NpdmKernelCapabilityEntryNumber_MiscParams = 13,
|
|
NpdmKernelCapabilityEntryNumber_KernelVersion = 14,
|
|
NpdmKernelCapabilityEntryNumber_HandleTableSize = 15,
|
|
NpdmKernelCapabilityEntryNumber_MiscFlags = 16
|
|
} NpdmKernelCapabilityEntryNumber;
|
|
|
|
typedef enum {
|
|
NpdmKernelCapabilityEntryValue_ThreadInfo = BIT(NpdmKernelCapabilityEntryNumber_ThreadInfo) - 1,
|
|
NpdmKernelCapabilityEntryValue_EnableSystemCalls = BIT(NpdmKernelCapabilityEntryNumber_EnableSystemCalls) - 1,
|
|
NpdmKernelCapabilityEntryValue_MemoryMap = BIT(NpdmKernelCapabilityEntryNumber_MemoryMap) - 1,
|
|
NpdmKernelCapabilityEntryValue_IoMemoryMap = BIT(NpdmKernelCapabilityEntryNumber_IoMemoryMap) - 1,
|
|
NpdmKernelCapabilityEntryValue_MemoryRegionMap = BIT(NpdmKernelCapabilityEntryNumber_MemoryRegionMap) - 1,
|
|
NpdmKernelCapabilityEntryValue_EnableInterrupts = BIT(NpdmKernelCapabilityEntryNumber_EnableInterrupts) - 1,
|
|
NpdmKernelCapabilityEntryValue_MiscParams = BIT(NpdmKernelCapabilityEntryNumber_MiscParams) - 1,
|
|
NpdmKernelCapabilityEntryValue_KernelVersion = BIT(NpdmKernelCapabilityEntryNumber_KernelVersion) - 1,
|
|
NpdmKernelCapabilityEntryValue_HandleTableSize = BIT(NpdmKernelCapabilityEntryNumber_HandleTableSize) - 1,
|
|
NpdmKernelCapabilityEntryValue_MiscFlags = BIT(NpdmKernelCapabilityEntryNumber_MiscFlags) - 1
|
|
} NpdmKernelCapabilityEntryValue;
|
|
|
|
/// ThreadInfo entry for the KernelCapability descriptor.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_ThreadInfo; ///< Always set to NpdmKernelCapabilityEntryValue_ThreadInfo.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 lowest_priority : 6;
|
|
u32 highest_priority : 6;
|
|
u32 min_core_number : 8;
|
|
u32 max_core_number : 8;
|
|
} NpdmThreadInfo;
|
|
|
|
NXDT_ASSERT(NpdmThreadInfo, 0x4);
|
|
|
|
/// System call table.
|
|
typedef enum {
|
|
///< System calls for index 0.
|
|
NpdmSystemCallId_Reserved1 = BIT(0),
|
|
NpdmSystemCallId_SetHeapSize = BIT(1),
|
|
NpdmSystemCallId_SetMemoryPermission = BIT(2),
|
|
NpdmSystemCallId_SetMemoryAttribute = BIT(3),
|
|
NpdmSystemCallId_MapMemory = BIT(4),
|
|
NpdmSystemCallId_UnmapMemory = BIT(5),
|
|
NpdmSystemCallId_QueryMemory = BIT(6),
|
|
NpdmSystemCallId_ExitProcess = BIT(7),
|
|
NpdmSystemCallId_CreateThread = BIT(8),
|
|
NpdmSystemCallId_StartThread = BIT(9),
|
|
NpdmSystemCallId_ExitThread = BIT(10),
|
|
NpdmSystemCallId_SleepThread = BIT(11),
|
|
NpdmSystemCallId_GetThreadPriority = BIT(12),
|
|
NpdmSystemCallId_SetThreadPriority = BIT(13),
|
|
NpdmSystemCallId_GetThreadCoreMask = BIT(14),
|
|
NpdmSystemCallId_SetThreadCoreMask = BIT(15),
|
|
NpdmSystemCallId_GetCurrentProcessorNumber = BIT(16),
|
|
NpdmSystemCallId_SignalEvent = BIT(17),
|
|
NpdmSystemCallId_ClearEvent = BIT(18),
|
|
NpdmSystemCallId_MapSharedMemory = BIT(19),
|
|
NpdmSystemCallId_UnmapSharedMemory = BIT(20),
|
|
NpdmSystemCallId_CreateTransferMemory = BIT(21),
|
|
NpdmSystemCallId_CloseHandle = BIT(22),
|
|
NpdmSystemCallId_ResetSignal = BIT(23),
|
|
|
|
///< System calls for index 1.
|
|
NpdmSystemCallId_WaitSynchronization = BIT(0),
|
|
NpdmSystemCallId_CancelSynchronization = BIT(1),
|
|
NpdmSystemCallId_ArbitrateLock = BIT(2),
|
|
NpdmSystemCallId_ArbitrateUnlock = BIT(3),
|
|
NpdmSystemCallId_WaitProcessWideKeyAtomic = BIT(4),
|
|
NpdmSystemCallId_SignalProcessWideKey = BIT(5),
|
|
NpdmSystemCallId_GetSystemTick = BIT(6),
|
|
NpdmSystemCallId_ConnectToNamedPort = BIT(7),
|
|
NpdmSystemCallId_SendSyncRequestLight = BIT(8),
|
|
NpdmSystemCallId_SendSyncRequest = BIT(9),
|
|
NpdmSystemCallId_SendSyncRequestWithUserBuffer = BIT(10),
|
|
NpdmSystemCallId_SendAsyncRequestWithUserBuffer = BIT(11),
|
|
NpdmSystemCallId_GetProcessId = BIT(12),
|
|
NpdmSystemCallId_GetThreadId = BIT(13),
|
|
NpdmSystemCallId_Break = BIT(14),
|
|
NpdmSystemCallId_OutputDebugString = BIT(15),
|
|
NpdmSystemCallId_ReturnFromException = BIT(16),
|
|
NpdmSystemCallId_GetInfo = BIT(17),
|
|
NpdmSystemCallId_FlushEntireDataCache = BIT(18),
|
|
NpdmSystemCallId_FlushDataCache = BIT(19),
|
|
NpdmSystemCallId_MapPhysicalMemory = BIT(20),
|
|
NpdmSystemCallId_UnmapPhysicalMemory = BIT(21),
|
|
NpdmSystemCallId_GetDebugFutureThreadInfo = BIT(22), ///< Old: SystemCallId_GetFutureThreadInfo.
|
|
NpdmSystemCallId_GetLastThreadInfo = BIT(23),
|
|
|
|
///< System calls for index 2.
|
|
NpdmSystemCallId_GetResourceLimitLimitValue = BIT(0),
|
|
NpdmSystemCallId_GetResourceLimitCurrentValue = BIT(1),
|
|
NpdmSystemCallId_SetThreadActivity = BIT(2),
|
|
NpdmSystemCallId_GetThreadContext3 = BIT(3),
|
|
NpdmSystemCallId_WaitForAddress = BIT(4),
|
|
NpdmSystemCallId_SignalToAddress = BIT(5),
|
|
NpdmSystemCallId_SynchronizePreemptionState = BIT(6),
|
|
NpdmSystemCallId_Reserved2 = BIT(7),
|
|
NpdmSystemCallId_Reserved3 = BIT(8),
|
|
NpdmSystemCallId_Reserved4 = BIT(9),
|
|
NpdmSystemCallId_Reserved5 = BIT(10),
|
|
NpdmSystemCallId_Reserved6 = BIT(11),
|
|
NpdmSystemCallId_KernelDebug = BIT(12),
|
|
NpdmSystemCallId_ChangeKernelTraceState = BIT(13),
|
|
NpdmSystemCallId_Reserved7 = BIT(14),
|
|
NpdmSystemCallId_Reserved8 = BIT(15),
|
|
NpdmSystemCallId_CreateSession = BIT(16),
|
|
NpdmSystemCallId_AcceptSession = BIT(17),
|
|
NpdmSystemCallId_ReplyAndReceiveLight = BIT(18),
|
|
NpdmSystemCallId_ReplyAndReceive = BIT(19),
|
|
NpdmSystemCallId_ReplyAndReceiveWithUserBuffer = BIT(20),
|
|
NpdmSystemCallId_CreateEvent = BIT(21),
|
|
NpdmSystemCallId_Reserved9 = BIT(22),
|
|
NpdmSystemCallId_Reserved10 = BIT(23),
|
|
|
|
///< System calls for index 3.
|
|
NpdmSystemCallId_MapPhysicalMemoryUnsafe = BIT(0),
|
|
NpdmSystemCallId_UnmapPhysicalMemoryUnsafe = BIT(1),
|
|
NpdmSystemCallId_SetUnsafeLimit = BIT(2),
|
|
NpdmSystemCallId_CreateCodeMemory = BIT(3),
|
|
NpdmSystemCallId_ControlCodeMemory = BIT(4),
|
|
NpdmSystemCallId_SleepSystem = BIT(5),
|
|
NpdmSystemCallId_ReadWriteRegister = BIT(6),
|
|
NpdmSystemCallId_SetProcessActivity = BIT(7),
|
|
NpdmSystemCallId_CreateSharedMemory = BIT(8),
|
|
NpdmSystemCallId_MapTransferMemory = BIT(9),
|
|
NpdmSystemCallId_UnmapTransferMemory = BIT(10),
|
|
NpdmSystemCallId_CreateInterruptEvent = BIT(11),
|
|
NpdmSystemCallId_QueryPhysicalAddress = BIT(12),
|
|
NpdmSystemCallId_QueryIoMapping = BIT(13),
|
|
NpdmSystemCallId_CreateDeviceAddressSpace = BIT(14),
|
|
NpdmSystemCallId_AttachDeviceAddressSpace = BIT(15),
|
|
NpdmSystemCallId_DetachDeviceAddressSpace = BIT(16),
|
|
NpdmSystemCallId_MapDeviceAddressSpaceByForce = BIT(17),
|
|
NpdmSystemCallId_MapDeviceAddressSpaceAligned = BIT(18),
|
|
NpdmSystemCallId_MapDeviceAddressSpace = BIT(19),
|
|
NpdmSystemCallId_UnmapDeviceAddressSpace = BIT(20),
|
|
NpdmSystemCallId_InvalidateProcessDataCache = BIT(21),
|
|
NpdmSystemCallId_StoreProcessDataCache = BIT(22),
|
|
NpdmSystemCallId_FlushProcessDataCache = BIT(23),
|
|
|
|
///< System calls for index 4.
|
|
NpdmSystemCallId_DebugActiveProcess = BIT(0),
|
|
NpdmSystemCallId_BreakDebugProcess = BIT(1),
|
|
NpdmSystemCallId_TerminateDebugProcess = BIT(2),
|
|
NpdmSystemCallId_GetDebugEvent = BIT(3),
|
|
NpdmSystemCallId_ContinueDebugEvent = BIT(4),
|
|
NpdmSystemCallId_GetProcessList = BIT(5),
|
|
NpdmSystemCallId_GetThreadList = BIT(6),
|
|
NpdmSystemCallId_GetDebugThreadContext = BIT(7),
|
|
NpdmSystemCallId_SetDebugThreadContext = BIT(8),
|
|
NpdmSystemCallId_QueryDebugProcessMemory = BIT(9),
|
|
NpdmSystemCallId_ReadDebugProcessMemory = BIT(10),
|
|
NpdmSystemCallId_WriteDebugProcessMemory = BIT(11),
|
|
NpdmSystemCallId_SetHardwareBreakPoint = BIT(12),
|
|
NpdmSystemCallId_GetDebugThreadParam = BIT(13),
|
|
NpdmSystemCallId_Reserved11 = BIT(14),
|
|
NpdmSystemCallId_GetSystemInfo = BIT(15),
|
|
NpdmSystemCallId_CreatePort = BIT(16),
|
|
NpdmSystemCallId_ManageNamedPort = BIT(17),
|
|
NpdmSystemCallId_ConnectToPort = BIT(18),
|
|
NpdmSystemCallId_SetProcessMemoryPermission = BIT(19),
|
|
NpdmSystemCallId_MapProcessMemory = BIT(20),
|
|
NpdmSystemCallId_UnmapProcessMemory = BIT(21),
|
|
NpdmSystemCallId_QueryProcessMemory = BIT(22),
|
|
NpdmSystemCallId_MapProcessCodeMemory = BIT(23),
|
|
|
|
///< System calls for index 5.
|
|
NpdmSystemCallId_UnmapProcessCodeMemory = BIT(0),
|
|
NpdmSystemCallId_CreateProcess = BIT(1),
|
|
NpdmSystemCallId_StartProcess = BIT(2),
|
|
NpdmSystemCallId_TerminateProcess = BIT(3),
|
|
NpdmSystemCallId_GetProcessInfo = BIT(4),
|
|
NpdmSystemCallId_CreateResourceLimit = BIT(5),
|
|
NpdmSystemCallId_SetResourceLimitLimitValue = BIT(6),
|
|
NpdmSystemCallId_CallSecureMonitor = BIT(7),
|
|
|
|
NpdmSystemCallId_Count = 0xC0 ///< Total values supported by this enum.
|
|
} NpdmSystemCallId;
|
|
|
|
/// EnableSystemCalls entry for the KernelCapability descriptor.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableSystemCalls; ///< Always set to NpdmKernelCapabilityEntryValue_EnableSystemCalls.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 system_call_ids : 24; ///< NpdmSystemCallId.
|
|
u32 index : 3; ///< System calls index.
|
|
} NpdmEnableSystemCalls;
|
|
|
|
NXDT_ASSERT(NpdmEnableSystemCalls, 0x4);
|
|
|
|
typedef enum {
|
|
NpdmPermissionType_RW = 0,
|
|
NpdmPermissionType_RO = 1
|
|
} NpdmPermissionType;
|
|
|
|
typedef enum {
|
|
NpdmMappingType_Io = 0,
|
|
NpdmMappingType_Static = 1
|
|
} NpdmMappingType;
|
|
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 begin_address : 24; ///< begin_address << 12.
|
|
u32 permission_type : 1; ///< NpdmPermissionType.
|
|
} NpdmMemoryMapType1;
|
|
|
|
NXDT_ASSERT(NpdmMemoryMapType1, 0x4);
|
|
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 size : 20; ///< size << 12.
|
|
u32 reserved : 4;
|
|
u32 mapping_type : 1; ///< NpdmMappingType.
|
|
} NpdmMemoryMapType2;
|
|
|
|
NXDT_ASSERT(NpdmMemoryMapType2, 0x4);
|
|
|
|
/// MemoryMap entry for the KernelCapability descriptor.
|
|
/// These are always stored in pairs of MemoryMapType1 + MemoryMapType2 entries.
|
|
typedef struct {
|
|
union {
|
|
NpdmMemoryMapType1 type1;
|
|
NpdmMemoryMapType2 type2;
|
|
};
|
|
} NpdmMemoryMap;
|
|
|
|
NXDT_ASSERT(NpdmMemoryMap, 0x4);
|
|
|
|
/// IoMemoryMap entry for the KernelCapability descriptor.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_IoMemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_IoMemoryMap.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 begin_address : 24; ///< begin_address << 12.
|
|
} NpdmIoMemoryMap;
|
|
|
|
NXDT_ASSERT(NpdmIoMemoryMap, 0x4);
|
|
|
|
typedef enum {
|
|
NpdmRegionType_NoMapping = 0,
|
|
NpdmRegionType_KernelTraceBuffer = 1,
|
|
NpdmRegionType_OnMemoryBootImage = 2,
|
|
NpdmRegionType_DTB = 3
|
|
} NpdmRegionType;
|
|
|
|
/// MemoryRegionMap entry for the KernelCapability descriptor.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryRegionMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryRegionMap.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 region_type_1 : 6; ///< NpdmRegionType.
|
|
u32 permission_type_1 : 1; ///< NpdmPermissionType.
|
|
u32 region_type_2 : 6; ///< NpdmRegionType.
|
|
u32 permission_type_2 : 1; ///< NpdmPermissionType.
|
|
u32 region_type_3 : 6; ///< NpdmRegionType.
|
|
u32 permission_type_3 : 1; ///< NpdmPermissionType.
|
|
} NpdmMemoryRegionMap;
|
|
|
|
NXDT_ASSERT(NpdmMemoryRegionMap, 0x4);
|
|
|
|
/// EnableInterrupts entry for the KernelCapability descriptor.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableInterrupts; ///< Always set to NpdmKernelCapabilityEntryValue_EnableInterrupts.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 interrupt_number_1 : 10; ///< 0x3FF means empty.
|
|
u32 interrupt_number_2 : 10; ///< 0x3FF means empty.
|
|
} NpdmEnableInterrupts;
|
|
|
|
NXDT_ASSERT(NpdmEnableInterrupts, 0x4);
|
|
|
|
typedef enum {
|
|
NpdmProgramType_System = 0,
|
|
NpdmProgramType_Application = 1,
|
|
NpdmProgramType_Applet = 2
|
|
} NpdmProgramType;
|
|
|
|
/// MiscParams entry for the KernelCapability descriptor.
|
|
/// Defaults to 0 if this entry doesn't exist.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscParams; ///< Always set to NpdmKernelCapabilityEntryValue_MiscParams.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 program_type : 3; ///< NpdmProgramType.
|
|
u32 reserved : 15;
|
|
} NpdmMiscParams;
|
|
|
|
NXDT_ASSERT(NpdmMiscParams, 0x4);
|
|
|
|
/// KernelVersion entry for the KernelCapability descriptor.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_KernelVersion; ///< Always set to NpdmKernelCapabilityEntryValue_KernelVersion.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 minor_version : 4;
|
|
u32 major_version : 13;
|
|
} NpdmKernelVersion;
|
|
|
|
NXDT_ASSERT(NpdmKernelVersion, 0x4);
|
|
|
|
/// HandleTableSize entry for the KernelCapability descriptor.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_HandleTableSize; ///< Always set to NpdmKernelCapabilityEntryValue_HandleTableSize.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 handle_table_size : 10;
|
|
u32 reserved : 6;
|
|
} NpdmHandleTableSize;
|
|
|
|
NXDT_ASSERT(NpdmHandleTableSize, 0x4);
|
|
|
|
/// MiscFlags entry for the KernelCapability descriptor.
|
|
typedef struct {
|
|
u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscFlags; ///< Always set to NpdmKernelCapabilityEntryValue_MiscFlags.
|
|
u32 padding : 1; ///< Always set to zero.
|
|
u32 enable_debug : 1;
|
|
u32 force_debug : 1;
|
|
u32 reserved : 13;
|
|
} NpdmMiscFlags;
|
|
|
|
NXDT_ASSERT(NpdmMiscFlags, 0x4);
|
|
|
|
/// KernelCapability descriptor. Part of the ACID and ACI0 section bodies.
|
|
/// This descriptor is composed of a variable number of u32 entries. Thus, the entry count can be calculated by dividing the KernelCapability descriptor size by 4.
|
|
/// The entry type is identified by a pattern of "01...11" (zero followed by ones) in the low u16, counting from the LSB. The variable number of ones must never exceed 16 (entirety of the low u16).
|
|
typedef struct {
|
|
u32 value;
|
|
} NpdmKernelCapabilityDescriptorEntry;
|
|
|
|
NXDT_ASSERT(NpdmKernelCapabilityDescriptorEntry, 0x4);
|
|
|
|
typedef struct {
|
|
NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which NPDM data is retrieved.
|
|
PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where the NPDM is stored.
|
|
PartitionFileSystemEntry *pfs_entry; ///< PartitionFileSystemEntry for the NPDM in the Program NCA FS section #0. Used to generate a NcaHierarchicalSha256Patch if needed.
|
|
NcaHierarchicalSha256Patch nca_patch; ///< NcaHierarchicalSha256Patch generated if NPDM modifications are needed. Used to seamlessly replace Program NCA data while writing it.
|
|
///< Bear in mind that generating a patch modifies the NCA context.
|
|
u8 *raw_data; ///< Pointer to a dynamically allocated buffer that holds the raw NPDM.
|
|
u64 raw_data_size; ///< Raw NPDM size. Kept here for convenience - this is part of 'pfs_entry'.
|
|
NpdmMetaHeader *meta_header; ///< Pointer to the NpdmMetaHeader within 'raw_data'.
|
|
NpdmAcidHeader *acid_header; ///< Pointer to the NpdmAcidHeader within 'raw_data'.
|
|
NpdmFsAccessControlDescriptor *acid_fac_descriptor; ///< Pointer to the NpdmFsAccessControlDescriptor within the NPDM ACID section.
|
|
NpdmSrvAccessControlDescriptorEntry *acid_sac_descriptor; ///< Pointer to the first NpdmSrvAccessControlDescriptorEntry within the NPDM ACID section, if available.
|
|
NpdmKernelCapabilityDescriptorEntry *acid_kc_descriptor; ///< Pointer to the first NpdmKernelCapabilityDescriptorEntry within the NPDM ACID section, if available.
|
|
NpdmAciHeader *aci_header; ///< Pointer to the NpdmAciHeader within 'raw_data'.
|
|
NpdmFsAccessControlData *aci_fac_data; ///< Pointer to the NpdmFsAccessControlData within the NPDM ACI0 section.
|
|
NpdmSrvAccessControlDescriptorEntry *aci_sac_descriptor; ///< Pointer to the first NpdmSrvAccessControlDescriptorEntry within the NPDM ACI0 section, if available.
|
|
NpdmKernelCapabilityDescriptorEntry *aci_kc_descriptor; ///< Pointer to the first NpdmKernelCapabilityDescriptorEntry within the NPDM ACI0 section, if available.
|
|
} NpdmContext;
|
|
|
|
/// Initializes a NpdmContext using a previously initialized PartitionFileSystemContext (which must belong to the ExeFS from a Program NCA).
|
|
bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx);
|
|
|
|
/// Changes the ACID public key from the NPDM in the input NpdmContext, updates the ACID signature from the NCA header in the underlying NCA context and generates a Partition FS entry patch.
|
|
bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx);
|
|
|
|
/// Writes data from the Partition FS entry patch in the input NpdmContext to the provided buffer.
|
|
void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_offset);
|
|
|
|
/// Helper inline functions.
|
|
|
|
NX_INLINE void npdmFreeContext(NpdmContext *npdm_ctx)
|
|
{
|
|
if (!npdm_ctx) return;
|
|
pfsFreeEntryPatch(&(npdm_ctx->nca_patch));
|
|
if (npdm_ctx->raw_data) free(npdm_ctx->raw_data);
|
|
memset(npdm_ctx, 0, sizeof(NpdmContext));
|
|
}
|
|
|
|
NX_INLINE bool npdmIsValidContext(NpdmContext *npdm_ctx)
|
|
{
|
|
return (npdm_ctx && npdm_ctx->nca_ctx && npdm_ctx->pfs_ctx && npdm_ctx->pfs_entry && npdm_ctx->raw_data && npdm_ctx->raw_data_size && npdm_ctx->meta_header && npdm_ctx->acid_header && \
|
|
npdm_ctx->acid_fac_descriptor && \
|
|
((npdm_ctx->acid_header->srv_access_control_size && npdm_ctx->acid_sac_descriptor) || (!npdm_ctx->acid_header->srv_access_control_size && !npdm_ctx->acid_sac_descriptor)) && \
|
|
((npdm_ctx->acid_header->kernel_capability_size && npdm_ctx->acid_kc_descriptor) || (!npdm_ctx->acid_header->kernel_capability_size && !npdm_ctx->acid_kc_descriptor)) && \
|
|
npdm_ctx->aci_header && npdm_ctx->aci_fac_data && \
|
|
((npdm_ctx->aci_header->srv_access_control_size && npdm_ctx->aci_sac_descriptor) || (!npdm_ctx->aci_header->srv_access_control_size && !npdm_ctx->aci_sac_descriptor)) && \
|
|
((npdm_ctx->aci_header->kernel_capability_size && npdm_ctx->aci_kc_descriptor) || (!npdm_ctx->aci_header->kernel_capability_size && !npdm_ctx->aci_kc_descriptor)));
|
|
}
|
|
|
|
NX_INLINE u32 npdmGetKernelCapabilityDescriptorEntryValue(NpdmKernelCapabilityDescriptorEntry *entry)
|
|
{
|
|
return (entry ? (((entry->value + 1) & ~entry->value) - 1) : 0);
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* __NPDM_H__ */
|