1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-26 04:02:11 +00:00

Some changes.

* Placed C++ extern "C" blocks inside include guards.

* Added a "clean_all" rule to the Makefile to avoid recompiling libusbhsfs after each time "clean" is used.

* Added static asserts for all structs that may need it throughout the code.

* Preprocessor macros are now used to generate certificate and ticket structs.
This commit is contained in:
Pablo Curiel 2021-03-24 13:25:19 -04:00
parent e0949bba6b
commit 3cb6ef93aa
36 changed files with 577 additions and 330 deletions

View file

@ -158,7 +158,7 @@ ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif endif
.PHONY: $(BUILD) clean all .PHONY: $(BUILD) clean clean_all all
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
all: $(BUILD) all: $(BUILD)
@ -173,9 +173,10 @@ $(BUILD): usbhsfs
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
clean: clean:
@echo clean ... @echo clean ...
@$(MAKE) --no-print-directory -C libusbhsfs clean
@rm -fr $(BUILD) *.pfs0 *.nso *.nro *.nacp *.elf @rm -fr $(BUILD) *.pfs0 *.nso *.nro *.nacp *.elf
clean_all: clean
@$(MAKE) --no-print-directory -C libusbhsfs clean
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
else else

View file

@ -20,13 +20,13 @@
#pragma once #pragma once
#ifndef __AES_H__
#define __AES_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __AES_H__
#define __AES_H__
/// Performs an AES-128-XTS crypto operation using the non-standard Nintendo XTS tweak. /// Performs an AES-128-XTS crypto operation using the non-standard Nintendo XTS tweak.
/// The Aes128XtsContext element should have been previously initialized with aes128XtsContextCreate(). 'encrypt' should match the value of 'is_encryptor' used with that call. /// The Aes128XtsContext element should have been previously initialized with aes128XtsContextCreate(). 'encrypt' should match the value of 'is_encryptor' used with that call.
/// 'dst' and 'src' can both point to the same address. /// 'dst' and 'src' can both point to the same address.
@ -84,8 +84,8 @@ NX_INLINE void aes128CtrUpdatePartialCtrEx(u8 *ctr, u32 ctr_val, u64 offset)
} }
} }
#endif /* __AES_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __AES_H__ */

View file

@ -21,13 +21,13 @@
#pragma once #pragma once
#ifndef __BFTTF_H__
#define __BFTTF_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __BFTTF_H__
#define __BFTTF_H__
/// Loosely based on PlSharedFontType. /// Loosely based on PlSharedFontType.
typedef enum { typedef enum {
BfttfFontType_Standard = 0, ///< Japan, US and Europe BfttfFontType_Standard = 0, ///< Japan, US and Europe
@ -56,8 +56,8 @@ void bfttfExit(void);
/// Returns a specific BFTTF font using the provided BfttfFontType. /// Returns a specific BFTTF font using the provided BfttfFontType.
bool bfttfGetFontByType(BfttfFontData *font, u8 font_type); bool bfttfGetFontByType(BfttfFontData *font, u8 font_type);
#endif /* __BFTTF_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __BFTTF_H__ */

View file

@ -21,15 +21,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __BKTR_H__ #ifndef __BKTR_H__
#define __BKTR_H__ #define __BKTR_H__
#include "romfs.h" #include "romfs.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum { typedef enum {
BktrIndirectStorageIndex_Original = 0, BktrIndirectStorageIndex_Original = 0,
BktrIndirectStorageIndex_Patch = 1 BktrIndirectStorageIndex_Patch = 1
@ -43,6 +43,8 @@ typedef struct {
} BktrIndirectStorageEntry; } BktrIndirectStorageEntry;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(BktrIndirectStorageEntry, 0x14);
typedef struct { typedef struct {
u32 index; u32 index;
u32 entry_count; u32 entry_count;
@ -51,6 +53,8 @@ typedef struct {
u8 reserved[0x3FF0 % sizeof(BktrIndirectStorageEntry)]; u8 reserved[0x3FF0 % sizeof(BktrIndirectStorageEntry)];
} BktrIndirectStorageBucket; } BktrIndirectStorageBucket;
NXDT_ASSERT(BktrIndirectStorageBucket, 0x4000);
typedef struct { typedef struct {
u32 index; u32 index;
u32 bucket_count; u32 bucket_count;
@ -59,12 +63,16 @@ typedef struct {
BktrIndirectStorageBucket indirect_storage_buckets[]; BktrIndirectStorageBucket indirect_storage_buckets[];
} BktrIndirectStorageBlock; } BktrIndirectStorageBlock;
NXDT_ASSERT(BktrIndirectStorageBlock, 0x4000);
typedef struct { typedef struct {
u64 offset; u64 offset;
u32 size; u32 size;
u32 generation; u32 generation;
} BktrAesCtrExStorageEntry; } BktrAesCtrExStorageEntry;
NXDT_ASSERT(BktrAesCtrExStorageEntry, 0x10);
typedef struct { typedef struct {
u32 index; u32 index;
u32 entry_count; u32 entry_count;
@ -72,6 +80,8 @@ typedef struct {
BktrAesCtrExStorageEntry aes_ctr_ex_storage_entries[0x3FF]; BktrAesCtrExStorageEntry aes_ctr_ex_storage_entries[0x3FF];
} BktrAesCtrExStorageBucket; } BktrAesCtrExStorageBucket;
NXDT_ASSERT(BktrAesCtrExStorageBucket, 0x4000);
typedef struct { typedef struct {
u32 index; u32 index;
u32 bucket_count; u32 bucket_count;
@ -80,6 +90,8 @@ typedef struct {
BktrAesCtrExStorageBucket aes_ctr_ex_storage_buckets[]; BktrAesCtrExStorageBucket aes_ctr_ex_storage_buckets[];
} BktrAesCtrExStorageBlock; } BktrAesCtrExStorageBlock;
NXDT_ASSERT(BktrAesCtrExStorageBlock, 0x4000);
typedef struct { typedef struct {
RomFileSystemContext base_romfs_ctx; ///< Base NCA RomFS context. RomFileSystemContext base_romfs_ctx; ///< Base NCA RomFS context.
RomFileSystemContext patch_romfs_ctx; ///< Update NCA RomFS context. Must be used with RomFS directory/file entry functions, because it holds the updated directory/file tables. RomFileSystemContext patch_romfs_ctx; ///< Update NCA RomFS context. Must be used with RomFS directory/file entry functions, because it holds the updated directory/file tables.
@ -157,8 +169,8 @@ NX_INLINE bool bktrGeneratePathFromFileEntry(BktrContext *ctx, RomFileSystemFile
return (ctx ? romfsGeneratePathFromFileEntry(&(ctx->patch_romfs_ctx), file_entry, out_path, out_path_size, illegal_char_replace_type) : false); return (ctx ? romfsGeneratePathFromFileEntry(&(ctx->patch_romfs_ctx), file_entry, out_path, out_path_size, illegal_char_replace_type) : false);
} }
#endif /* __BKTR_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __BKTR_H__ */

View file

@ -20,18 +20,93 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __CERT_H__ #ifndef __CERT_H__
#define __CERT_H__ #define __CERT_H__
#include "signature.h" #include "signature.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SIGNED_CERT_MAX_SIZE sizeof(CertSigRsa4096PubKeyRsa4096) #define SIGNED_CERT_MAX_SIZE sizeof(CertSigRsa4096PubKeyRsa4096)
#define SIGNED_CERT_MIN_SIZE sizeof(CertSigHmac160PubKeyEcc480) #define SIGNED_CERT_MIN_SIZE sizeof(CertSigHmac160PubKeyEcc480)
#define GENERATE_CERT_STRUCT(sigtype, pubkeytype, certsize) \
\
typedef struct { \
SignatureBlock##sigtype sig_block; \
CertCommonBlock cert_common_block; \
CertPublicKeyBlock##pubkeytype pub_key_block; \
} CertSig##sigtype##PubKey##pubkeytype; \
\
NXDT_ASSERT(CertSig##sigtype##PubKey##pubkeytype, certsize);
typedef enum {
CertPubKeyType_Rsa4096 = 0,
CertPubKeyType_Rsa2048 = 1,
CertPubKeyType_Ecc480 = 2
} CertPubKeyType;
/// Placed after the certificate signature block.
typedef struct {
char issuer[0x40];
u32 pub_key_type; ///< CertPubKeyType. Always stored using big endian byte order.
char name[0x40];
u32 date; ///< Stored using big endian byte order.
} CertCommonBlock;
NXDT_ASSERT(CertCommonBlock, 0x88);
/// RSA-4096 public key block. Placed after the certificate common block.
typedef struct {
u8 public_key[0x200];
u32 public_exponent;
u8 padding[0x34];
} CertPublicKeyBlockRsa4096;
NXDT_ASSERT(CertPublicKeyBlockRsa4096, 0x238);
/// RSA-2048 public key block. Placed after the certificate common block.
typedef struct {
u8 public_key[0x100];
u32 public_exponent;
u8 padding[0x34];
} CertPublicKeyBlockRsa2048;
NXDT_ASSERT(CertPublicKeyBlockRsa2048, 0x138);
/// ECC public key block. Placed after the certificate common block.
typedef struct {
u8 public_key[0x3C];
u8 padding[0x3C];
} CertPublicKeyBlockEcc480;
NXDT_ASSERT(CertPublicKeyBlockEcc480, 0x78);
/// All certificates generated below use a big endian sig_type field.
/// Certificates with RSA-4096 signatures.
GENERATE_CERT_STRUCT(Rsa4096, Rsa4096, 0x500); /// pub_key_type field must be CertPubKeyType_Rsa4096.
GENERATE_CERT_STRUCT(Rsa4096, Rsa2048, 0x400); /// pub_key_type field must be CertPubKeyType_Rsa2048.
GENERATE_CERT_STRUCT(Rsa4096, Ecc480, 0x340); /// pub_key_type field must be CertPubKeyType_Ecc480.
/// Certificates with RSA-2048 signatures.
GENERATE_CERT_STRUCT(Rsa2048, Rsa4096, 0x400); /// pub_key_type field must be CertPubKeyType_Rsa4096.
GENERATE_CERT_STRUCT(Rsa2048, Rsa2048, 0x300); /// pub_key_type field must be CertPubKeyType_Rsa2048.
GENERATE_CERT_STRUCT(Rsa2048, Ecc480, 0x240); /// pub_key_type field must be CertPubKeyType_Ecc480.
/// Certificates with ECC signatures.
GENERATE_CERT_STRUCT(Ecc480, Rsa4096, 0x340); /// pub_key_type field must be CertPubKeyType_Rsa4096.
GENERATE_CERT_STRUCT(Ecc480, Rsa2048, 0x240); /// pub_key_type field must be CertPubKeyType_Rsa2048.
GENERATE_CERT_STRUCT(Ecc480, Ecc480, 0x180); /// pub_key_type field must be CertPubKeyType_Ecc480.
/// Certificates with HMAC signatures.
GENERATE_CERT_STRUCT(Hmac160, Rsa4096, 0x300); /// pub_key_type field must be CertPubKeyType_Rsa4096.
GENERATE_CERT_STRUCT(Hmac160, Rsa2048, 0x200); /// pub_key_type field must be CertPubKeyType_Rsa2048.
GENERATE_CERT_STRUCT(Hmac160, Ecc480, 0x140); /// pub_key_type field must be CertPubKeyType_Ecc480.
/// Certificate type.
typedef enum { typedef enum {
CertType_None = 0, CertType_None = 0,
CertType_SigRsa4096_PubKeyRsa4096 = 1, CertType_SigRsa4096_PubKeyRsa4096 = 1,
@ -48,110 +123,6 @@ typedef enum {
CertType_SigHmac160_PubKeyEcc480 = 12 CertType_SigHmac160_PubKeyEcc480 = 12
} CertType; } CertType;
/// Always stored using big endian byte order.
typedef enum {
CertPubKeyType_Rsa4096 = 0,
CertPubKeyType_Rsa2048 = 1,
CertPubKeyType_Ecc480 = 2
} CertPubKeyType;
/// Placed after the certificate signature block.
typedef struct {
char issuer[0x40];
u32 pub_key_type; ///< CertPubKeyType. Stored using big endian byte order.
char name[0x40];
u32 date; ///< Stored using big endian byte order.
} CertCommonBlock;
typedef struct {
u8 public_key[0x200];
u32 public_exponent;
u8 padding[0x34];
} CertPublicKeyBlockRsa4096;
typedef struct {
u8 public_key[0x100];
u32 public_exponent;
u8 padding[0x34];
} CertPublicKeyBlockRsa2048;
typedef struct {
u8 public_key[0x3C];
u8 padding[0x3C];
} CertPublicKeyBlockEcc480;
typedef struct {
SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa4096.
CertPublicKeyBlockRsa4096 pub_key_block;
} CertSigRsa4096PubKeyRsa4096;
typedef struct {
SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa2048.
CertPublicKeyBlockRsa2048 pub_key_block;
} CertSigRsa4096PubKeyRsa2048;
typedef struct {
SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Ecc480.
CertPublicKeyBlockEcc480 pub_key_block;
} CertSigRsa4096PubKeyEcc480;
typedef struct {
SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa4096.
CertPublicKeyBlockRsa4096 pub_key_block;
} CertSigRsa2048PubKeyRsa4096;
typedef struct {
SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa2048.
CertPublicKeyBlockRsa2048 pub_key_block;
} CertSigRsa2048PubKeyRsa2048;
typedef struct {
SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Ecc480.
CertPublicKeyBlockEcc480 pub_key_block;
} CertSigRsa2048PubKeyEcc480;
typedef struct {
SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa4096.
CertPublicKeyBlockRsa4096 pub_key_block;
} CertSigEcc480PubKeyRsa4096;
typedef struct {
SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa2048.
CertPublicKeyBlockRsa2048 pub_key_block;
} CertSigEcc480PubKeyRsa2048;
typedef struct {
SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Ecc480.
CertPublicKeyBlockEcc480 pub_key_block;
} CertSigEcc480PubKeyEcc480;
typedef struct {
SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa4096.
CertPublicKeyBlockRsa4096 pub_key_block;
} CertSigHmac160PubKeyRsa4096;
typedef struct {
SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa2048.
CertPublicKeyBlockRsa2048 pub_key_block;
} CertSigHmac160PubKeyRsa2048;
typedef struct {
SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order.
CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Ecc480.
CertPublicKeyBlockEcc480 pub_key_block;
} CertSigHmac160PubKeyEcc480;
/// Used to store certificate type, size and raw data. /// Used to store certificate type, size and raw data.
typedef struct { typedef struct {
u8 type; ///< CertType. u8 type; ///< CertType.
@ -244,8 +215,8 @@ NX_INLINE u64 certGetSignedCertificateHashAreaSize(void *buf)
return ((u64)sizeof(CertCommonBlock) + certGetPublicKeyBlockSize(__builtin_bswap32(cert_common_block->pub_key_type))); return ((u64)sizeof(CertCommonBlock) + certGetPublicKeyBlockSize(__builtin_bswap32(cert_common_block->pub_key_type)));
} }
#endif /* __CERT_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __CERT_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __CNMT_H__ #ifndef __CNMT_H__
#define __CNMT_H__ #define __CNMT_H__
#include "pfs.h" #include "pfs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CNMT_DIGEST_SIZE SHA256_HASH_SIZE #define CNMT_DIGEST_SIZE SHA256_HASH_SIZE
/// Equivalent to NcmContentMetaAttribute. /// Equivalent to NcmContentMetaAttribute.
@ -64,12 +64,16 @@ typedef struct {
u8 reserved_2[0x4]; u8 reserved_2[0x4];
} ContentMetaPackagedContentMetaHeader; } ContentMetaPackagedContentMetaHeader;
NXDT_ASSERT(ContentMetaPackagedContentMetaHeader, 0x20);
/// Extended header for the SystemUpdate title. /// Extended header for the SystemUpdate title.
/// Equivalent to NcmSystemUpdateMetaExtendedHeader. /// Equivalent to NcmSystemUpdateMetaExtendedHeader.
typedef struct { typedef struct {
u32 extended_data_size; u32 extended_data_size;
} ContentMetaSystemUpdateMetaExtendedHeader; } ContentMetaSystemUpdateMetaExtendedHeader;
NXDT_ASSERT(ContentMetaSystemUpdateMetaExtendedHeader, 0x4);
/// Extended header for Application titles. /// Extended header for Application titles.
/// Equivalent to NcmApplicationMetaExtendedHeader, but using VersionType1 structs. /// Equivalent to NcmApplicationMetaExtendedHeader, but using VersionType1 structs.
typedef struct { typedef struct {
@ -78,6 +82,8 @@ typedef struct {
VersionType1 required_application_version; VersionType1 required_application_version;
} ContentMetaApplicationMetaExtendedHeader; } ContentMetaApplicationMetaExtendedHeader;
NXDT_ASSERT(ContentMetaApplicationMetaExtendedHeader, 0x10);
/// Extended header for Patch titles. /// Extended header for Patch titles.
/// Equivalent to NcmPatchMetaExtendedHeader, but using a VersionType1 struct. /// Equivalent to NcmPatchMetaExtendedHeader, but using a VersionType1 struct.
typedef struct { typedef struct {
@ -87,6 +93,8 @@ typedef struct {
u8 reserved[0x8]; u8 reserved[0x8];
} ContentMetaPatchMetaExtendedHeader; } ContentMetaPatchMetaExtendedHeader;
NXDT_ASSERT(ContentMetaPatchMetaExtendedHeader, 0x18);
/// Extended header for AddOnContent titles. /// Extended header for AddOnContent titles.
/// Equivalent to NcmAddOnContentMetaExtendedHeader, but using a VersionType1 struct. /// Equivalent to NcmAddOnContentMetaExtendedHeader, but using a VersionType1 struct.
typedef struct { typedef struct {
@ -95,6 +103,8 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} ContentMetaAddOnContentMetaExtendedHeader; } ContentMetaAddOnContentMetaExtendedHeader;
NXDT_ASSERT(ContentMetaAddOnContentMetaExtendedHeader, 0x10);
/// Extended header for Delta titles. /// Extended header for Delta titles.
typedef struct { typedef struct {
u64 application_id; u64 application_id;
@ -102,6 +112,8 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} ContentMetaDeltaMetaExtendedHeader; } ContentMetaDeltaMetaExtendedHeader;
NXDT_ASSERT(ContentMetaDeltaMetaExtendedHeader, 0x10);
typedef enum { typedef enum {
ContentMetaFirmwareVariationVersion_Invalid = 0, ContentMetaFirmwareVariationVersion_Invalid = 0,
ContentMetaFirmwareVariationVersion_V1 = 1, ContentMetaFirmwareVariationVersion_V1 = 1,
@ -120,12 +132,16 @@ typedef struct {
u32 variation_count; ///< Determines how many firmware variation entries are available after this header. u32 variation_count; ///< Determines how many firmware variation entries are available after this header.
} ContentMetaSystemUpdateMetaExtendedDataHeader; } ContentMetaSystemUpdateMetaExtendedDataHeader;
NXDT_ASSERT(ContentMetaSystemUpdateMetaExtendedDataHeader, 0x8);
/// Used if the firmware variation version matches ContentMetaFirmwareVariationVersion_V1. /// Used if the firmware variation version matches ContentMetaFirmwareVariationVersion_V1.
typedef struct { typedef struct {
u32 firmware_variation_id; u32 firmware_variation_id;
u8 reserved[0x1C]; u8 reserved[0x1C];
} ContentMetaFirmwareVariationInfoV1; } ContentMetaFirmwareVariationInfoV1;
NXDT_ASSERT(ContentMetaFirmwareVariationInfoV1, 0x20);
/// Used if the firmware variation version matches ContentMetaFirmwareVariationVersion_V2. /// Used if the firmware variation version matches ContentMetaFirmwareVariationVersion_V2.
typedef struct { typedef struct {
bool refer_to_base; bool refer_to_base;
@ -134,6 +150,8 @@ typedef struct {
u8 reserved_2[0x18]; u8 reserved_2[0x18];
} ContentMetaFirmwareVariationInfoV2; } ContentMetaFirmwareVariationInfoV2;
NXDT_ASSERT(ContentMetaFirmwareVariationInfoV2, 0x20);
/// Header for the extended data region in Patch titles, pointed to by the extended header. /// Header for the extended data region in Patch titles, pointed to by the extended header.
/// This is followed by: /// This is followed by:
/// * 'history_count' ContentMetaPatchHistoryHeader entries. /// * 'history_count' ContentMetaPatchHistoryHeader entries.
@ -153,6 +171,8 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} ContentMetaPatchMetaExtendedDataHeader; } ContentMetaPatchMetaExtendedDataHeader;
NXDT_ASSERT(ContentMetaPatchMetaExtendedDataHeader, 0x1C);
typedef struct { typedef struct {
NcmContentMetaKey content_meta_key; NcmContentMetaKey content_meta_key;
u8 digest[CNMT_DIGEST_SIZE]; u8 digest[CNMT_DIGEST_SIZE];
@ -160,6 +180,8 @@ typedef struct {
u8 reserved[0x6]; u8 reserved[0x6];
} ContentMetaPatchHistoryHeader; } ContentMetaPatchHistoryHeader;
NXDT_ASSERT(ContentMetaPatchHistoryHeader, 0x38);
typedef struct { typedef struct {
u64 source_patch_id; u64 source_patch_id;
u64 destination_patch_id; u64 destination_patch_id;
@ -169,6 +191,8 @@ typedef struct {
u8 reserved[0x8]; u8 reserved[0x8];
} ContentMetaPatchDeltaHistory; } ContentMetaPatchDeltaHistory;
NXDT_ASSERT(ContentMetaPatchDeltaHistory, 0x28);
typedef struct { typedef struct {
u64 source_patch_id; u64 source_patch_id;
u64 destination_patch_id; u64 destination_patch_id;
@ -180,6 +204,8 @@ typedef struct {
u8 reserved_2[0x6]; u8 reserved_2[0x6];
} ContentMetaPatchDeltaHeader; } ContentMetaPatchDeltaHeader;
NXDT_ASSERT(ContentMetaPatchDeltaHeader, 0x28);
typedef enum { typedef enum {
ContentMetaUpdateType_ApplyAsDelta = 0, ContentMetaUpdateType_ApplyAsDelta = 0,
ContentMetaUpdateType_Overwrite = 1, ContentMetaUpdateType_Overwrite = 1,
@ -201,11 +227,15 @@ typedef struct {
} ContentMetaFragmentSet; } ContentMetaFragmentSet;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(ContentMetaFragmentSet, 0x34);
typedef struct { typedef struct {
u16 content_info_index; u16 content_info_index;
u16 fragment_index; u16 fragment_index;
} ContentMetaFragmentIndicator; } ContentMetaFragmentIndicator;
NXDT_ASSERT(ContentMetaFragmentIndicator, 0x4);
/// Header for the extended data region in Delta titles, pointed to by the extended header. /// Header for the extended data region in Delta titles, pointed to by the extended header.
/// This is followed by: /// This is followed by:
/// * 'fragment_set_count' ContentMetaFragmentSet entries. /// * 'fragment_set_count' ContentMetaFragmentSet entries.
@ -219,6 +249,8 @@ typedef struct {
u8 reserved[0x6]; u8 reserved[0x6];
} ContentMetaDeltaMetaExtendedDataHeader; } ContentMetaDeltaMetaExtendedDataHeader;
NXDT_ASSERT(ContentMetaDeltaMetaExtendedDataHeader, 0x20);
typedef struct { typedef struct {
NcaContext *nca_ctx; ///< Pointer to the NCA context for the Meta NCA from which CNMT data is retrieved. NcaContext *nca_ctx; ///< Pointer to the NCA context for the Meta NCA from which CNMT data is retrieved.
PartitionFileSystemContext pfs_ctx; ///< PartitionFileSystemContext for the Meta NCA FS section #0, which is where the CNMT is stored. PartitionFileSystemContext pfs_ctx; ///< PartitionFileSystemContext for the Meta NCA FS section #0, which is where the CNMT is stored.
@ -293,8 +325,8 @@ NX_INLINE u32 cnmtGetRequiredTitleVersion(ContentMetaContext *cnmt_ctx)
((VersionType1*)(cnmt_ctx->extended_header + sizeof(u64)))->value : 0); ((VersionType1*)(cnmt_ctx->extended_header + sizeof(u64)))->value : 0);
} }
#endif /* __CNMT_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __CNMT_H__ */

View file

@ -23,13 +23,6 @@
#ifndef __COMMON_H__ #ifndef __COMMON_H__
#define __COMMON_H__ #define __COMMON_H__
#ifndef __cplusplus
# include <stdatomic.h>
#else
# include <atomic>
# define _Atomic(X) std::atomic< X >
#endif
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -45,6 +38,13 @@
#include <assert.h> #include <assert.h>
#include <switch.h> #include <switch.h>
#ifndef __cplusplus
#include <stdatomic.h>
#else
#include <atomic>
#define _Atomic(X) std::atomic< X >
#endif
#include "log.h" #include "log.h"
#include "ums.h" #include "ums.h"
@ -56,6 +56,8 @@
#define FAT32_FILESIZE_LIMIT (u64)0xFFFFFFFF /* 4 GiB - 1 (4294967295 bytes). */ #define FAT32_FILESIZE_LIMIT (u64)0xFFFFFFFF /* 4 GiB - 1 (4294967295 bytes). */
#define NXDT_ASSERT(name, size) static_assert(sizeof(name) == (size), "Bad size for " #name "! Expected " #size ".")
/// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{major_relstep}.{minor_relstep}". /// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{major_relstep}.{minor_relstep}".
/// Referenced by multiple header files. /// Referenced by multiple header files.
typedef struct { typedef struct {
@ -71,6 +73,8 @@ typedef struct {
}; };
} VersionType1; } VersionType1;
NXDT_ASSERT(VersionType1, 0x4);
/// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{relstep}". /// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{relstep}".
/// Only used by GameCardFwMode and NcaSdkAddOnVersion. /// Only used by GameCardFwMode and NcaSdkAddOnVersion.
typedef struct { typedef struct {
@ -85,6 +89,8 @@ typedef struct {
}; };
} VersionType2; } VersionType2;
NXDT_ASSERT(VersionType2, 0x4);
/// These are set in main(). /// These are set in main().
extern int g_argc; extern int g_argc;
extern char **g_argv; extern char **g_argv;

View file

@ -23,19 +23,19 @@
#pragma once #pragma once
#ifndef __CRC32_FAST_H__
#define __CRC32_FAST_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __CRC32_FAST_H__
#define __CRC32_FAST_H__
/// Calculates a CRC32 checksum over the provided input buffer. Checksum calculation in chunks is supported. /// Calculates a CRC32 checksum over the provided input buffer. Checksum calculation in chunks is supported.
/// CRC32 calculation state is both read from and saved to 'crc', which should be zero during the first call to this function. /// CRC32 calculation state is both read from and saved to 'crc', which should be zero during the first call to this function.
void crc32FastCalculate(const void *data, u64 n_bytes, u32 *crc); void crc32FastCalculate(const void *data, u64 n_bytes, u32 *crc);
#endif /* __CRC32_FAST_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __CRC32_FAST_H__ */

View file

@ -79,6 +79,8 @@ typedef struct {
u16 st_shndx; ///< Holds the relevant section header table index. u16 st_shndx; ///< Holds the relevant section header table index.
} Elf32Symbol; } Elf32Symbol;
NXDT_ASSERT(Elf32Symbol, 0x10);
typedef struct { typedef struct {
u32 st_name; ///< Symbol name offset within dynamic string table. u32 st_name; ///< Symbol name offset within dynamic string table.
u8 st_info; ///< Symbol type (lower nibble) and binding attributes (upper nibble). u8 st_info; ///< Symbol type (lower nibble) and binding attributes (upper nibble).
@ -88,4 +90,6 @@ typedef struct {
u64 st_size; ///< Symbol size. u64 st_size; ///< Symbol size.
} Elf64Symbol; } Elf64Symbol;
NXDT_ASSERT(Elf64Symbol, 0x18);
#endif /* __ELF_SYMBOL_H__ */ #endif /* __ELF_SYMBOL_H__ */

View file

@ -21,13 +21,13 @@
#pragma once #pragma once
#ifndef __ES_H__
#define __ES_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __ES_H__
#define __ES_H__
Result esInitialize(void); Result esInitialize(void);
void esExit(void); void esExit(void);
@ -36,8 +36,8 @@ Result esCountPersonalizedTicket(s32 *out_count);
Result esListCommonTicket(s32 *out_entries_written, FsRightsId *out_ids, s32 count); Result esListCommonTicket(s32 *out_entries_written, FsRightsId *out_ids, s32 count);
Result esListPersonalizedTicket(s32 *out_entries_written, FsRightsId *out_ids, s32 count); Result esListPersonalizedTicket(s32 *out_entries_written, FsRightsId *out_ids, s32 count);
#endif /* __ES_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __ES_H__ */

View file

@ -20,13 +20,13 @@
#pragma once #pragma once
#ifndef __FS_EXT_H__
#define __FS_EXT_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __FS_EXT_H__
#define __FS_EXT_H__
#define GAMECARD_CERT_MAGIC 0x43455254 /* "CERT". */ #define GAMECARD_CERT_MAGIC 0x43455254 /* "CERT". */
/// Located at offset 0x7000 in the gamecard image. /// Located at offset 0x7000 in the gamecard image.
@ -41,6 +41,8 @@ typedef struct {
u8 encrypted_data[0xD0]; u8 encrypted_data[0xD0];
} FsGameCardCertificate; } FsGameCardCertificate;
NXDT_ASSERT(FsGameCardCertificate, 0x200);
/// IFileSystemProxy. /// IFileSystemProxy.
Result fsOpenGameCardStorage(FsStorage *out, const FsGameCardHandle *handle, u32 partition); Result fsOpenGameCardStorage(FsStorage *out, const FsGameCardHandle *handle, u32 partition);
Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier *out); Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier *out);
@ -49,8 +51,8 @@ Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier *out);
Result fsDeviceOperatorUpdatePartitionInfo(FsDeviceOperator *d, const FsGameCardHandle *handle, u32 *out_title_version, u64 *out_title_id); Result fsDeviceOperatorUpdatePartitionInfo(FsDeviceOperator *d, const FsGameCardHandle *handle, u32 *out_title_version, u64 *out_title_id);
Result fsDeviceOperatorGetGameCardDeviceCertificate(FsDeviceOperator *d, const FsGameCardHandle *handle, FsGameCardCertificate *out); Result fsDeviceOperatorGetGameCardDeviceCertificate(FsDeviceOperator *d, const FsGameCardHandle *handle, FsGameCardCertificate *out);
#endif /* __FS_EXT_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __FS_EXT_H__ */

View file

@ -61,6 +61,8 @@ typedef struct {
GameCardInitialData initial_data; GameCardInitialData initial_data;
} GameCardSecurityInformation; } GameCardSecurityInformation;
NXDT_ASSERT(GameCardSecurityInformation, 0x600);
/* Global variables. */ /* Global variables. */
static Mutex g_gameCardMutex = 0; static Mutex g_gameCardMutex = 0;

View file

@ -20,16 +20,16 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __GAMECARD_H__ #ifndef __GAMECARD_H__
#define __GAMECARD_H__ #define __GAMECARD_H__
#include "fs_ext.h" #include "fs_ext.h"
#include "hfs.h" #include "hfs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define GAMECARD_HEAD_MAGIC 0x48454144 /* "HEAD". */ #define GAMECARD_HEAD_MAGIC 0x48454144 /* "HEAD". */
#define GAMECARD_MEDIA_UNIT_SIZE 0x200 #define GAMECARD_MEDIA_UNIT_SIZE 0x200
@ -45,6 +45,8 @@ typedef struct {
u8 reserved[0x8]; ///< Just zeroes. u8 reserved[0x8]; ///< Just zeroes.
} GameCardKeySource; } GameCardKeySource;
NXDT_ASSERT(GameCardKeySource, 0x10);
/// Plaintext area. Dumped from FS program memory. /// Plaintext area. Dumped from FS program memory.
typedef struct { typedef struct {
GameCardKeySource key_source; GameCardKeySource key_source;
@ -54,12 +56,16 @@ typedef struct {
u8 reserved[0x1C4]; u8 reserved[0x1C4];
} GameCardInitialData; } GameCardInitialData;
NXDT_ASSERT(GameCardInitialData, 0x200);
/// Encrypted using AES-128-CTR with the key and IV/counter from the `GameCardTitleKeyEncryption` section. Assumed to be all zeroes in retail gamecards. /// Encrypted using AES-128-CTR with the key and IV/counter from the `GameCardTitleKeyEncryption` section. Assumed to be all zeroes in retail gamecards.
typedef struct { typedef struct {
u8 titlekey[0x10]; ///< Decrypted titlekey from the `GameCardInitialData` section. u8 titlekey[0x10]; ///< Decrypted titlekey from the `GameCardInitialData` section.
u8 reserved[0xCF0]; u8 reserved[0xCF0];
} GameCardTitleKey; } GameCardTitleKey;
NXDT_ASSERT(GameCardTitleKey, 0xD00);
/// Encrypted using RSA-2048-OAEP and a private OAEP key from AuthoringTool. Assumed to be all zeroes in retail gamecards. /// Encrypted using RSA-2048-OAEP and a private OAEP key from AuthoringTool. Assumed to be all zeroes in retail gamecards.
typedef struct { typedef struct {
u8 titlekey_encryption_key[0x10]; ///< Used as the AES-128-CTR key for the `GameCardTitleKey` section. Randomly generated during XCI creation by AuthoringTool. u8 titlekey_encryption_key[0x10]; ///< Used as the AES-128-CTR key for the `GameCardTitleKey` section. Randomly generated during XCI creation by AuthoringTool.
@ -67,6 +73,8 @@ typedef struct {
u8 reserved[0xE0]; u8 reserved[0xE0];
} GameCardTitleKeyEncryption; } GameCardTitleKeyEncryption;
NXDT_ASSERT(GameCardTitleKeyEncryption, 0x100);
/// Used to secure communications between the Lotus and the inserted gamecard. /// Used to secure communications between the Lotus and the inserted gamecard.
/// Precedes the gamecard header. /// Precedes the gamecard header.
typedef struct { typedef struct {
@ -75,6 +83,8 @@ typedef struct {
GameCardTitleKeyEncryption titlekey_encryption; GameCardTitleKeyEncryption titlekey_encryption;
} GameCardKeyArea; } GameCardKeyArea;
NXDT_ASSERT(GameCardKeyArea, 0x1000);
typedef enum { typedef enum {
GameCardKekIndex_Version0 = 0, GameCardKekIndex_Version0 = 0,
GameCardKekIndex_VersionForDev = 1 GameCardKekIndex_VersionForDev = 1
@ -85,6 +95,8 @@ typedef struct {
u8 titlekey_dec_index : 4; u8 titlekey_dec_index : 4;
} GameCardKeyIndex; } GameCardKeyIndex;
NXDT_ASSERT(GameCardKeyIndex, 0x1);
typedef enum { typedef enum {
GameCardRomSize_1GiB = 0xFA, GameCardRomSize_1GiB = 0xFA,
GameCardRomSize_2GiB = 0xF8, GameCardRomSize_2GiB = 0xF8,
@ -144,6 +156,8 @@ typedef struct {
u8 reserved_2[0x38]; u8 reserved_2[0x38];
} GameCardHeaderEncryptedArea; } GameCardHeaderEncryptedArea;
NXDT_ASSERT(GameCardHeaderEncryptedArea, 0x70);
/// Placed after the `GameCardKeyArea` section. /// Placed after the `GameCardKeyArea` section.
typedef struct { typedef struct {
u8 signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over the rest of the header. u8 signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over the rest of the header.
@ -169,6 +183,8 @@ typedef struct {
GameCardHeaderEncryptedArea encrypted_area; GameCardHeaderEncryptedArea encrypted_area;
} GameCardHeader; } GameCardHeader;
NXDT_ASSERT(GameCardHeader, 0x200);
typedef enum { typedef enum {
GameCardStatus_NotInserted = 0, GameCardStatus_NotInserted = 0,
GameCardStatus_InsertedAndInfoNotLoaded = 1, ///< Most likely related to the "nogc" patch being enabled. Means nothing at all can be done with the inserted gamecard. GameCardStatus_InsertedAndInfoNotLoaded = 1, ///< Most likely related to the "nogc" patch being enabled. Means nothing at all can be done with the inserted gamecard.
@ -238,8 +254,8 @@ bool gamecardGetHashFileSystemContext(u8 hfs_partition_type, HashFileSystemConte
/// If you need to get entry information by index, just retrieve the Hash FS context for the target partition and use Hash FS functions on it. /// If you need to get entry information by index, just retrieve the Hash FS context for the target partition and use Hash FS functions on it.
bool gamecardGetHashFileSystemEntryInfoByName(u8 hfs_partition_type, const char *entry_name, u64 *out_offset, u64 *out_size); bool gamecardGetHashFileSystemEntryInfoByName(u8 hfs_partition_type, const char *entry_name, u64 *out_offset, u64 *out_size);
#endif /* __GAMECARD_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __GAMECARD_H__ */

View file

@ -20,13 +20,13 @@
#pragma once #pragma once
#ifndef __HFS_H__
#define __HFS_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __HFS_H__
#define __HFS_H__
#define HFS0_MAGIC 0x48465330 /* "HFS0". */ #define HFS0_MAGIC 0x48465330 /* "HFS0". */
typedef struct { typedef struct {
@ -36,6 +36,8 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} HashFileSystemHeader; } HashFileSystemHeader;
NXDT_ASSERT(HashFileSystemHeader, 0x10);
typedef struct { typedef struct {
u64 offset; u64 offset;
u64 size; u64 size;
@ -45,6 +47,8 @@ typedef struct {
u8 hash[SHA256_HASH_SIZE]; u8 hash[SHA256_HASH_SIZE];
} HashFileSystemEntry; } HashFileSystemEntry;
NXDT_ASSERT(HashFileSystemEntry, 0x40);
/// Internally used by gamecard functions. /// Internally used by gamecard functions.
/// Use gamecardGetHashFileSystemContext() to retrieve a Hash FS context. /// Use gamecardGetHashFileSystemContext() to retrieve a Hash FS context.
typedef struct { typedef struct {
@ -121,8 +125,8 @@ NX_INLINE HashFileSystemEntry *hfsGetEntryByName(HashFileSystemContext *ctx, con
return hfsGetEntryByIndex(ctx, idx); return hfsGetEntryByIndex(ctx, idx);
} }
#endif /* __HFS_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __HFS_H__ */

View file

@ -22,13 +22,13 @@
#pragma once #pragma once
#ifndef __KEYS_H__
#define __KEYS_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __KEYS_H__
#define __KEYS_H__
bool keysLoadNcaKeyset(void); bool keysLoadNcaKeyset(void);
const u8 *keysGetNcaHeaderKey(void); const u8 *keysGetNcaHeaderKey(void);
@ -37,8 +37,8 @@ const u8 *keysGetEticketRsaKek(bool personalized);
const u8 *keysGetTitlekek(u8 key_generation); const u8 *keysGetTitlekek(u8 key_generation);
const u8 *keysGetKeyAreaEncryptionKey(u8 key_generation, u8 kaek_index); const u8 *keysGetKeyAreaEncryptionKey(u8 key_generation, u8 kaek_index);
#endif /* __KEYS_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __KEYS_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __LEGAL_INFO_H__ #ifndef __LEGAL_INFO_H__
#define __LEGAL_INFO_H__ #define __LEGAL_INFO_H__
#include "nca.h" #include "nca.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct { typedef struct {
NcaContext *nca_ctx; ///< Pointer to the NCA context for the LegalInformation NCA from which XML data is retrieved. NcaContext *nca_ctx; ///< Pointer to the NCA context for the LegalInformation NCA from which XML data is retrieved.
char *authoring_tool_xml; ///< Pointer to a dynamically allocated, NULL-terminated buffer that holds AuthoringTool-like XML data. char *authoring_tool_xml; ///< Pointer to a dynamically allocated, NULL-terminated buffer that holds AuthoringTool-like XML data.
@ -47,8 +47,8 @@ NX_INLINE void legalInfoFreeContext(LegalInfoContext *legal_info_ctx)
memset(legal_info_ctx, 0, sizeof(LegalInfoContext)); memset(legal_info_ctx, 0, sizeof(LegalInfoContext));
} }
#endif /* __LEGAL_INFO_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __LEGAL_INFO_H__ */

View file

@ -20,13 +20,13 @@
#pragma once #pragma once
#ifndef __LOG_H__
#define __LOG_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __LOG_H__
#define __LOG_H__
/// Helper macros. /// Helper macros.
#define LOG_MSG(fmt, ...) logWriteFormattedStringToLogFile(__func__, fmt, ##__VA_ARGS__) #define LOG_MSG(fmt, ...) logWriteFormattedStringToLogFile(__func__, fmt, ##__VA_ARGS__)
#define LOG_MSG_BUF(dst, dst_size, fmt, ...) logWriteFormattedStringToBuffer(dst, dst_size, __func__, fmt, ##__VA_ARGS__) #define LOG_MSG_BUF(dst, dst_size, fmt, ...) logWriteFormattedStringToBuffer(dst, dst_size, __func__, fmt, ##__VA_ARGS__)
@ -58,8 +58,8 @@ void logGetLastMessage(char *dst, size_t dst_size);
/// Use with caution. /// Use with caution.
void logControlMutex(bool lock); void logControlMutex(bool lock);
#endif /* __LOG_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __LOG_H__ */

View file

@ -21,13 +21,13 @@
#pragma once #pragma once
#ifndef __MEM_H__
#define __MEM_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __MEM_H__
#define __MEM_H__
typedef enum { typedef enum {
MemoryProgramSegmentType_Text = BIT(0), MemoryProgramSegmentType_Text = BIT(0),
MemoryProgramSegmentType_Rodata = BIT(1), MemoryProgramSegmentType_Rodata = BIT(1),
@ -59,8 +59,8 @@ NX_INLINE void memFreeMemoryLocation(MemoryLocation *location)
location->data_size = 0; location->data_size = 0;
} }
#endif /* __MEM_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __MEM_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NACP_H__ #ifndef __NACP_H__
#define __NACP_H__ #define __NACP_H__
#include "romfs.h" #include "romfs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NACP_MAX_ICON_SIZE 0x20000 /* 128 KiB. */ #define NACP_MAX_ICON_SIZE 0x20000 /* 128 KiB. */
typedef struct { typedef struct {
@ -36,6 +36,8 @@ typedef struct {
char publisher[0x100]; char publisher[0x100];
} NacpTitle; } NacpTitle;
NXDT_ASSERT(NacpTitle, 0x300);
typedef enum { typedef enum {
NacpStartupUserAccount_None = 0, NacpStartupUserAccount_None = 0,
NacpStartupUserAccount_Required = 1, NacpStartupUserAccount_Required = 1,
@ -180,6 +182,8 @@ typedef struct {
s8 reserved[0x13]; s8 reserved[0x13];
} NacpRatingAge; } NacpRatingAge;
NXDT_ASSERT(NacpRatingAge, 0x20);
typedef enum { typedef enum {
NacpLogoType_LicensedByNintendo = 0, NacpLogoType_LicensedByNintendo = 0,
NacpLogoType_DistributedByNintendo = 1, ///< Removed. NacpLogoType_DistributedByNintendo = 1, ///< Removed.
@ -252,15 +256,21 @@ typedef struct {
u64 memory_size; u64 memory_size;
} NacpJitConfiguration; } NacpJitConfiguration;
NXDT_ASSERT(NacpJitConfiguration, 0x10);
typedef struct { typedef struct {
u16 index : 15; u16 index : 15;
u16 continue_set : 1; ///< Called "flag" by Nintendo, which isn't really great. u16 continue_set : 1; ///< Called "flag" by Nintendo, which isn't really great.
} NacpDescriptors; } NacpDescriptors;
NXDT_ASSERT(NacpDescriptors, 0x2);
typedef struct { typedef struct {
NacpDescriptors descriptors[0x20]; NacpDescriptors descriptors[0x20];
} NacpRequiredAddOnContentsSetBinaryDescriptor; } NacpRequiredAddOnContentsSetBinaryDescriptor;
NXDT_ASSERT(NacpRequiredAddOnContentsSetBinaryDescriptor, 0x40);
typedef enum { typedef enum {
NacpPlayReportPermission_None = 0, NacpPlayReportPermission_None = 0,
NacpPlayReportPermission_TargetMarketing = 1, NacpPlayReportPermission_TargetMarketing = 1,
@ -283,6 +293,8 @@ typedef struct {
u64 application_id[8]; u64 application_id[8];
} NacpAccessibleLaunchRequiredVersion; } NacpAccessibleLaunchRequiredVersion;
NXDT_ASSERT(NacpAccessibleLaunchRequiredVersion, 0x40);
typedef struct { typedef struct {
NacpTitle title[0x10]; NacpTitle title[0x10];
char isbn[0x25]; char isbn[0x25];
@ -346,6 +358,8 @@ typedef struct {
u8 reserved_6[0xBB8]; u8 reserved_6[0xBB8];
} _NacpStruct; } _NacpStruct;
NXDT_ASSERT(_NacpStruct, 0x4000);
typedef struct { typedef struct {
u8 language; ///< NacpLanguage. u8 language; ///< NacpLanguage.
u64 icon_size; ///< JPG icon size. Must not exceed NACP_MAX_ICON_SIZE. u64 icon_size; ///< JPG icon size. Must not exceed NACP_MAX_ICON_SIZE.
@ -455,8 +469,8 @@ NX_INLINE bool nacpIsValidContext(NacpContext *nacp_ctx)
return true; return true;
} }
#endif /* __NACP_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __NACP_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NCA_H__ #ifndef __NCA_H__
#define __NCA_H__ #define __NCA_H__
#include "tik.h" #include "tik.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NCA_FS_HEADER_COUNT 4 #define NCA_FS_HEADER_COUNT 4
#define NCA_FULL_HEADER_LENGTH (sizeof(NcaHeader) + (sizeof(NcaFsHeader) * NCA_FS_HEADER_COUNT)) #define NCA_FULL_HEADER_LENGTH (sizeof(NcaHeader) + (sizeof(NcaFsHeader) * NCA_FS_HEADER_COUNT))
@ -100,10 +100,14 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} NcaFsInfo; } NcaFsInfo;
NXDT_ASSERT(NcaFsInfo, 0x10);
typedef struct { typedef struct {
u8 hash[SHA256_HASH_SIZE]; u8 hash[SHA256_HASH_SIZE];
} NcaFsHeaderHash; } NcaFsHeaderHash;
NXDT_ASSERT(NcaFsHeaderHash, 0x20);
/// Encrypted NCA key area used to hold NCA FS section encryption keys. Zeroed out if the NCA uses titlekey crypto. /// Encrypted NCA key area used to hold NCA FS section encryption keys. Zeroed out if the NCA uses titlekey crypto.
/// Only the first 4 key entries are encrypted. /// Only the first 4 key entries are encrypted.
/// If a particular key entry is unused, it is zeroed out before this area is encrypted. /// If a particular key entry is unused, it is zeroed out before this area is encrypted.
@ -116,6 +120,8 @@ typedef struct {
u8 reserved[0xB0]; u8 reserved[0xB0];
} NcaEncryptedKeyArea; } NcaEncryptedKeyArea;
NXDT_ASSERT(NcaEncryptedKeyArea, 0x100);
/// First 0x400 bytes from every NCA. /// First 0x400 bytes from every NCA.
typedef struct { typedef struct {
u8 main_signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over header using a fixed key. u8 main_signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over header using a fixed key.
@ -138,6 +144,8 @@ typedef struct {
NcaEncryptedKeyArea encrypted_key_area; NcaEncryptedKeyArea encrypted_key_area;
} NcaHeader; } NcaHeader;
NXDT_ASSERT(NcaHeader, 0x400);
typedef enum { typedef enum {
NcaFsType_RomFs = 0, NcaFsType_RomFs = 0,
NcaFsType_PartitionFs = 1 NcaFsType_PartitionFs = 1
@ -163,6 +171,8 @@ typedef struct {
u64 size; u64 size;
} NcaRegion; } NcaRegion;
NXDT_ASSERT(NcaRegion, 0x10);
/// Used by NcaFsType_PartitionFs and NCA0 NcaFsType_RomFs. /// Used by NcaFsType_PartitionFs and NCA0 NcaFsType_RomFs.
typedef struct { typedef struct {
u8 master_hash[SHA256_HASH_SIZE]; u8 master_hash[SHA256_HASH_SIZE];
@ -171,6 +181,8 @@ typedef struct {
NcaRegion hash_region[NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT]; NcaRegion hash_region[NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT];
} NcaHierarchicalSha256Data; } NcaHierarchicalSha256Data;
NXDT_ASSERT(NcaHierarchicalSha256Data, 0x78);
typedef struct { typedef struct {
u64 offset; u64 offset;
u64 size; u64 size;
@ -178,10 +190,14 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} NcaHierarchicalIntegrityVerificationLevelInformation; } NcaHierarchicalIntegrityVerificationLevelInformation;
NXDT_ASSERT(NcaHierarchicalIntegrityVerificationLevelInformation, 0x18);
typedef struct { typedef struct {
u8 value[0x20]; u8 value[0x20];
} NcaSignatureSalt; } NcaSignatureSalt;
NXDT_ASSERT(NcaSignatureSalt, 0x20);
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
u32 max_level_count; ///< Always NCA_IVFC_MAX_LEVEL_COUNT. u32 max_level_count; ///< Always NCA_IVFC_MAX_LEVEL_COUNT.
@ -190,6 +206,8 @@ typedef struct {
} NcaInfoLevelHash; } NcaInfoLevelHash;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(NcaInfoLevelHash, 0xB4);
/// Used by NcaFsType_RomFs. /// Used by NcaFsType_RomFs.
typedef struct { typedef struct {
u32 magic; ///< "IVFC". u32 magic; ///< "IVFC".
@ -199,6 +217,8 @@ typedef struct {
u8 master_hash[SHA256_HASH_SIZE]; u8 master_hash[SHA256_HASH_SIZE];
} NcaIntegrityMetaInfo; } NcaIntegrityMetaInfo;
NXDT_ASSERT(NcaIntegrityMetaInfo, 0xE0);
typedef struct { typedef struct {
union { union {
struct { struct {
@ -214,6 +234,8 @@ typedef struct {
}; };
} NcaHashData; } NcaHashData;
NXDT_ASSERT(NcaHashData, 0xF8);
typedef struct { typedef struct {
u32 magic; ///< "BKTR". u32 magic; ///< "BKTR".
u32 version; ///< offset_count / node_count ? u32 version; ///< offset_count / node_count ?
@ -221,18 +243,24 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} NcaBucketTreeHeader; } NcaBucketTreeHeader;
NXDT_ASSERT(NcaBucketTreeHeader, 0x10);
typedef struct { typedef struct {
u64 offset; u64 offset;
u64 size; u64 size;
NcaBucketTreeHeader header; NcaBucketTreeHeader header;
} NcaBucketInfo; } NcaBucketInfo;
NXDT_ASSERT(NcaBucketInfo, 0x20);
/// Only used for NcaEncryptionType_AesCtrEx (PatchRomFs). /// Only used for NcaEncryptionType_AesCtrEx (PatchRomFs).
typedef struct { typedef struct {
NcaBucketInfo indirect_bucket; NcaBucketInfo indirect_bucket;
NcaBucketInfo aes_ctr_ex_bucket; NcaBucketInfo aes_ctr_ex_bucket;
} NcaPatchInfo; } NcaPatchInfo;
NXDT_ASSERT(NcaPatchInfo, 0x40);
typedef struct { typedef struct {
union { union {
u8 value[0x8]; u8 value[0x8];
@ -243,6 +271,8 @@ typedef struct {
}; };
} NcaAesCtrUpperIv; } NcaAesCtrUpperIv;
NXDT_ASSERT(NcaAesCtrUpperIv, 0x8);
/// Used in NCAs with sparse storage. /// Used in NCAs with sparse storage.
typedef struct { typedef struct {
NcaBucketInfo sparse_bucket; NcaBucketInfo sparse_bucket;
@ -251,6 +281,8 @@ typedef struct {
u8 reserved[0x6]; u8 reserved[0x6];
} NcaSparseInfo; } NcaSparseInfo;
NXDT_ASSERT(NcaSparseInfo, 0x30);
/// Four NCA FS headers are placed right after the 0x400 byte long NCA header in NCA2 and NCA3. /// Four NCA FS headers are placed right after the 0x400 byte long NCA header in NCA2 and NCA3.
/// NCA0 place the FS headers at the start sector from the NcaFsInfo entries. /// NCA0 place the FS headers at the start sector from the NcaFsInfo entries.
typedef struct { typedef struct {
@ -266,6 +298,8 @@ typedef struct {
u8 reserved_2[0x88]; u8 reserved_2[0x88];
} NcaFsHeader; } NcaFsHeader;
NXDT_ASSERT(NcaFsHeader, 0x200);
typedef enum { typedef enum {
NcaFsSectionType_PartitionFs = 0, ///< NcaFsType_PartitionFs + NcaHashType_HierarchicalSha256. NcaFsSectionType_PartitionFs = 0, ///< NcaFsType_PartitionFs + NcaHashType_HierarchicalSha256.
NcaFsSectionType_RomFs = 1, ///< NcaFsType_RomFs + NcaHashType_HierarchicalIntegrity. NcaFsSectionType_RomFs = 1, ///< NcaFsType_RomFs + NcaHashType_HierarchicalIntegrity.
@ -307,6 +341,8 @@ typedef struct {
u8 aes_ctr_ex[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtrEx crypto. u8 aes_ctr_ex[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtrEx crypto.
} NcaDecryptedKeyArea; } NcaDecryptedKeyArea;
NXDT_ASSERT(NcaDecryptedKeyArea, 0x40);
typedef struct { typedef struct {
u8 storage_id; ///< NcmStorageId. u8 storage_id; ///< NcmStorageId.
NcmContentStorage *ncm_storage; ///< Pointer to a NcmContentStorage instance. Used to read NCA data from eMMC/SD. NcmContentStorage *ncm_storage; ///< Pointer to a NcmContentStorage instance. Used to read NCA data from eMMC/SD.
@ -497,8 +533,8 @@ NX_INLINE void ncaFreeHierarchicalIntegrityPatch(NcaHierarchicalIntegrityPatch *
memset(patch, 0, sizeof(NcaHierarchicalIntegrityPatch)); memset(patch, 0, sizeof(NcaHierarchicalIntegrityPatch));
} }
#endif /* __NCA_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __NCA_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NPDM_H__ #ifndef __NPDM_H__
#define __NPDM_H__ #define __NPDM_H__
#include "pfs.h" #include "pfs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NPDM_META_MAGIC 0x4D455441 /* "META". */ #define NPDM_META_MAGIC 0x4D455441 /* "META". */
#define NPDM_ACID_MAGIC 0x41434944 /* "ACID". */ #define NPDM_ACID_MAGIC 0x41434944 /* "ACID". */
#define NPDM_ACI0_MAGIC 0x41434930 /* "ACI0". */ #define NPDM_ACI0_MAGIC 0x41434930 /* "ACI0". */
@ -53,6 +53,8 @@ typedef struct {
u8 reserved : 2; u8 reserved : 2;
} NpdmMetaFlags; } NpdmMetaFlags;
NXDT_ASSERT(NpdmMetaFlags, 0x1);
/// This is the start of every NPDM file. /// This is the start of every NPDM file.
/// This is followed by ACID and ACI0 sections, both with variable offsets and sizes. /// This is followed by ACID and ACI0 sections, both with variable offsets and sizes.
typedef struct { typedef struct {
@ -76,6 +78,8 @@ typedef struct {
u32 acid_size; u32 acid_size;
} NpdmMetaHeader; } NpdmMetaHeader;
NXDT_ASSERT(NpdmMetaHeader, 0x80);
typedef enum { typedef enum {
NpdmMemoryRegion_Application = 0, NpdmMemoryRegion_Application = 0,
NpdmMemoryRegion_Applet = 1, NpdmMemoryRegion_Applet = 1,
@ -94,6 +98,8 @@ typedef struct {
u32 reserved : 28; u32 reserved : 28;
} NpdmAcidFlags; } NpdmAcidFlags;
NXDT_ASSERT(NpdmAcidFlags, 0x4);
/// This is the start of an ACID section. /// 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). /// This is followed by FsAccessControl, SrvAccessControl and KernelCapability descriptors, each one aligned to a 0x10 byte boundary using zero padding (if needed).
typedef struct { typedef struct {
@ -114,6 +120,8 @@ typedef struct {
u8 reserved_2[0x8]; u8 reserved_2[0x8];
} NpdmAcidHeader; } NpdmAcidHeader;
NXDT_ASSERT(NpdmAcidHeader, 0x240);
/// This is the start of an ACI0 section. /// 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). /// 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 { typedef struct {
@ -130,6 +138,8 @@ typedef struct {
u8 reserved_3[0x8]; u8 reserved_3[0x8];
} NpdmAciHeader; } NpdmAciHeader;
NXDT_ASSERT(NpdmAciHeader, 0x40);
typedef enum { typedef enum {
NpdmFsAccessControlFlags_ApplicationInfo = BIT_LONG(0), NpdmFsAccessControlFlags_ApplicationInfo = BIT_LONG(0),
NpdmFsAccessControlFlags_BootModeControl = BIT_LONG(1), NpdmFsAccessControlFlags_BootModeControl = BIT_LONG(1),
@ -190,6 +200,8 @@ typedef struct {
} NpdmFsAccessControlDescriptor; } NpdmFsAccessControlDescriptor;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(NpdmFsAccessControlDescriptor, 0x2C);
/// FsAccessControl data. Part of the ACI0 section body. /// FsAccessControl data. Part of the ACI0 section body.
/// This is followed by: /// This is followed by:
/// * A NpdmFsAccessControlDataContentOwnerBlock if 'content_owner_info_size' is greater than zero. /// * A NpdmFsAccessControlDataContentOwnerBlock if 'content_owner_info_size' is greater than zero.
@ -207,11 +219,17 @@ typedef struct {
} NpdmFsAccessControlData; } NpdmFsAccessControlData;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(NpdmFsAccessControlData, 0x1C);
/// Placed after NpdmFsAccessControlData if its 'content_owner_info_size' member is greater than zero. /// Placed after NpdmFsAccessControlData if its 'content_owner_info_size' member is greater than zero.
#pragma pack(push, 1)
typedef struct { typedef struct {
u32 content_owner_id_count; u32 content_owner_id_count;
u64 content_owner_id[]; ///< 'content_owner_id_count' content owned IDs. u64 content_owner_id[]; ///< 'content_owner_id_count' content owned IDs.
} NpdmFsAccessControlDataContentOwnerBlock; } NpdmFsAccessControlDataContentOwnerBlock;
#pragma pack(pop)
NXDT_ASSERT(NpdmFsAccessControlDataContentOwnerBlock, 0x4);
typedef enum { typedef enum {
NpdmAccessibility_Read = BIT(0), NpdmAccessibility_Read = BIT(0),
@ -225,6 +243,8 @@ typedef struct {
u8 accessibility[]; ///< 'save_data_owner_id_count' NpdmAccessibility fields. u8 accessibility[]; ///< 'save_data_owner_id_count' NpdmAccessibility fields.
} NpdmFsAccessControlDataSaveDataOwnerBlock; } NpdmFsAccessControlDataSaveDataOwnerBlock;
NXDT_ASSERT(NpdmFsAccessControlDataSaveDataOwnerBlock, 0x4);
/// SrvAccessControl descriptor. Part of the ACID and ACI0 section bodies. /// 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. /// 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. /// Since the total number of services isn't stored anywhere, this descriptor must be parsed until its total size is reached.
@ -235,6 +255,8 @@ typedef struct {
char name[]; ///< Service name, stored without a NULL terminator. Supports the "*" wildcard character. char name[]; ///< Service name, stored without a NULL terminator. Supports the "*" wildcard character.
} NpdmSrvAccessControlDescriptorEntry; } NpdmSrvAccessControlDescriptorEntry;
NXDT_ASSERT(NpdmSrvAccessControlDescriptorEntry, 0x1);
typedef enum { typedef enum {
NpdmKernelCapabilityEntryNumber_ThreadInfo = 3, NpdmKernelCapabilityEntryNumber_ThreadInfo = 3,
NpdmKernelCapabilityEntryNumber_EnableSystemCalls = 4, NpdmKernelCapabilityEntryNumber_EnableSystemCalls = 4,
@ -271,6 +293,8 @@ typedef struct {
u32 max_core_number : 8; u32 max_core_number : 8;
} NpdmThreadInfo; } NpdmThreadInfo;
NXDT_ASSERT(NpdmThreadInfo, 0x4);
/// System call table. /// System call table.
typedef enum { typedef enum {
///< System calls for index 0. ///< System calls for index 0.
@ -423,6 +447,8 @@ typedef struct {
u32 index : 3; ///< System calls index. u32 index : 3; ///< System calls index.
} NpdmEnableSystemCalls; } NpdmEnableSystemCalls;
NXDT_ASSERT(NpdmEnableSystemCalls, 0x4);
typedef enum { typedef enum {
NpdmPermissionType_RW = 0, NpdmPermissionType_RW = 0,
NpdmPermissionType_RO = 1 NpdmPermissionType_RO = 1
@ -440,6 +466,8 @@ typedef struct {
u32 permission_type : 1; ///< NpdmPermissionType. u32 permission_type : 1; ///< NpdmPermissionType.
} NpdmMemoryMapType1; } NpdmMemoryMapType1;
NXDT_ASSERT(NpdmMemoryMapType1, 0x4);
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap. u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap.
u32 padding : 1; ///< Always set to zero. u32 padding : 1; ///< Always set to zero.
@ -448,6 +476,8 @@ typedef struct {
u32 mapping_type : 1; ///< NpdmMappingType. u32 mapping_type : 1; ///< NpdmMappingType.
} NpdmMemoryMapType2; } NpdmMemoryMapType2;
NXDT_ASSERT(NpdmMemoryMapType2, 0x4);
/// MemoryMap entry for the KernelCapability descriptor. /// MemoryMap entry for the KernelCapability descriptor.
/// These are always stored in pairs of MemoryMapType1 + MemoryMapType2 entries. /// These are always stored in pairs of MemoryMapType1 + MemoryMapType2 entries.
typedef struct { typedef struct {
@ -457,6 +487,8 @@ typedef struct {
}; };
} NpdmMemoryMap; } NpdmMemoryMap;
NXDT_ASSERT(NpdmMemoryMap, 0x4);
/// IoMemoryMap entry for the KernelCapability descriptor. /// IoMemoryMap entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_IoMemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_IoMemoryMap. u32 entry_value : NpdmKernelCapabilityEntryNumber_IoMemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_IoMemoryMap.
@ -464,6 +496,8 @@ typedef struct {
u32 begin_address : 24; ///< begin_address << 12. u32 begin_address : 24; ///< begin_address << 12.
} NpdmIoMemoryMap; } NpdmIoMemoryMap;
NXDT_ASSERT(NpdmIoMemoryMap, 0x4);
typedef enum { typedef enum {
NpdmRegionType_NoMapping = 0, NpdmRegionType_NoMapping = 0,
NpdmRegionType_KernelTraceBuffer = 1, NpdmRegionType_KernelTraceBuffer = 1,
@ -483,6 +517,8 @@ typedef struct {
u32 permission_type_3 : 1; ///< NpdmPermissionType. u32 permission_type_3 : 1; ///< NpdmPermissionType.
} NpdmMemoryRegionMap; } NpdmMemoryRegionMap;
NXDT_ASSERT(NpdmMemoryRegionMap, 0x4);
/// EnableInterrupts entry for the KernelCapability descriptor. /// EnableInterrupts entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableInterrupts; ///< Always set to NpdmKernelCapabilityEntryValue_EnableInterrupts. u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableInterrupts; ///< Always set to NpdmKernelCapabilityEntryValue_EnableInterrupts.
@ -491,6 +527,8 @@ typedef struct {
u32 interrupt_number_2 : 10; ///< 0x3FF means empty. u32 interrupt_number_2 : 10; ///< 0x3FF means empty.
} NpdmEnableInterrupts; } NpdmEnableInterrupts;
NXDT_ASSERT(NpdmEnableInterrupts, 0x4);
typedef enum { typedef enum {
NpdmProgramType_System = 0, NpdmProgramType_System = 0,
NpdmProgramType_Application = 1, NpdmProgramType_Application = 1,
@ -506,6 +544,8 @@ typedef struct {
u32 reserved : 15; u32 reserved : 15;
} NpdmMiscParams; } NpdmMiscParams;
NXDT_ASSERT(NpdmMiscParams, 0x4);
/// KernelVersion entry for the KernelCapability descriptor. /// KernelVersion entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_KernelVersion; ///< Always set to NpdmKernelCapabilityEntryValue_KernelVersion. u32 entry_value : NpdmKernelCapabilityEntryNumber_KernelVersion; ///< Always set to NpdmKernelCapabilityEntryValue_KernelVersion.
@ -514,6 +554,8 @@ typedef struct {
u32 major_version : 13; u32 major_version : 13;
} NpdmKernelVersion; } NpdmKernelVersion;
NXDT_ASSERT(NpdmKernelVersion, 0x4);
/// HandleTableSize entry for the KernelCapability descriptor. /// HandleTableSize entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_HandleTableSize; ///< Always set to NpdmKernelCapabilityEntryValue_HandleTableSize. u32 entry_value : NpdmKernelCapabilityEntryNumber_HandleTableSize; ///< Always set to NpdmKernelCapabilityEntryValue_HandleTableSize.
@ -522,6 +564,8 @@ typedef struct {
u32 reserved : 6; u32 reserved : 6;
} NpdmHandleTableSize; } NpdmHandleTableSize;
NXDT_ASSERT(NpdmHandleTableSize, 0x4);
/// MiscFlags entry for the KernelCapability descriptor. /// MiscFlags entry for the KernelCapability descriptor.
typedef struct { typedef struct {
u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscFlags; ///< Always set to NpdmKernelCapabilityEntryValue_MiscFlags. u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscFlags; ///< Always set to NpdmKernelCapabilityEntryValue_MiscFlags.
@ -531,6 +575,8 @@ typedef struct {
u32 reserved : 13; u32 reserved : 13;
} NpdmMiscFlags; } NpdmMiscFlags;
NXDT_ASSERT(NpdmMiscFlags, 0x4);
/// KernelCapability descriptor. Part of the ACID and ACI0 section bodies. /// 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. /// 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). /// 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).
@ -538,6 +584,8 @@ typedef struct {
u32 value; u32 value;
} NpdmKernelCapabilityDescriptorEntry; } NpdmKernelCapabilityDescriptorEntry;
NXDT_ASSERT(NpdmKernelCapabilityDescriptorEntry, 0x4);
typedef struct { typedef struct {
NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which NPDM data is retrieved. 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. PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where the NPDM is stored.
@ -592,8 +640,8 @@ NX_INLINE u32 npdmGetKernelCapabilityDescriptorEntryValue(NpdmKernelCapabilityDe
return (entry ? (((entry->value + 1) & ~entry->value) - 1) : 0); return (entry ? (((entry->value + 1) & ~entry->value) - 1) : 0);
} }
#endif /* __NPDM_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __NPDM_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __NSO_H__ #ifndef __NSO_H__
#define __NSO_H__ #define __NSO_H__
#include "pfs.h" #include "pfs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NSO_HEADER_MAGIC 0x4E534F30 /* "NSO0". */ #define NSO_HEADER_MAGIC 0x4E534F30 /* "NSO0". */
#define NSO_MOD_MAGIC 0x4D4F4430 /* "MOD0". */ #define NSO_MOD_MAGIC 0x4D4F4430 /* "MOD0". */
@ -47,11 +47,15 @@ typedef struct {
u32 size; ///< Decompressed segment size. u32 size; ///< Decompressed segment size.
} NsoSegmentInfo; } NsoSegmentInfo;
NXDT_ASSERT(NsoSegmentInfo, 0xC);
typedef struct { typedef struct {
u32 offset; ///< Relative to the .rodata segment start. u32 offset; ///< Relative to the .rodata segment start.
u32 size; u32 size;
} NsoSectionInfo; } NsoSectionInfo;
NXDT_ASSERT(NsoSectionInfo, 0x8);
/// This is the start of every NSO. /// This is the start of every NSO.
/// This is always followed by a NsoModuleName block. /// This is always followed by a NsoModuleName block.
typedef struct { typedef struct {
@ -73,11 +77,13 @@ typedef struct {
NsoSectionInfo api_info_section_info; NsoSectionInfo api_info_section_info;
NsoSectionInfo dynstr_section_info; NsoSectionInfo dynstr_section_info;
NsoSectionInfo dynsym_section_info; NsoSectionInfo dynsym_section_info;
u8 text_segment_hash[0x20]; ///< Decompressed .text segment SHA-256 checksum. u8 text_segment_hash[SHA256_HASH_SIZE]; ///< Decompressed .text segment SHA-256 checksum.
u8 rodata_segment_hash[0x20]; ///< Decompressed .rodata segment SHA-256 checksum. u8 rodata_segment_hash[SHA256_HASH_SIZE]; ///< Decompressed .rodata segment SHA-256 checksum.
u8 data_segment_hash[0x20]; ///< Decompressed .data segment SHA-256 checksum. u8 data_segment_hash[SHA256_HASH_SIZE]; ///< Decompressed .data segment SHA-256 checksum.
} NsoHeader; } NsoHeader;
NXDT_ASSERT(NsoHeader, 0x100);
/// Usually placed right after NsoHeader, but it's actual offset may vary. /// Usually placed right after NsoHeader, but it's actual offset may vary.
/// If the 'module_name_size' member from NsoHeader is greater than 1 and the 'name_length' element from NsoModuleName is greater than 0, 'name' will hold the module name. /// If the 'module_name_size' member from NsoHeader is greater than 1 and the 'name_length' element from NsoModuleName is greater than 0, 'name' will hold the module name.
typedef struct { typedef struct {
@ -85,12 +91,16 @@ typedef struct {
char name[]; char name[];
} NsoModuleName; } NsoModuleName;
NXDT_ASSERT(NsoModuleName, 0x1);
/// Placed at the very start of the decompressed .text segment. /// Placed at the very start of the decompressed .text segment.
typedef struct { typedef struct {
u32 entry_point; u32 entry_point;
u32 mod_offset; ///< NsoModHeader block offset (relative to the start of this header). Almost always set to 0x8 (the size of this struct). u32 mod_offset; ///< NsoModHeader block offset (relative to the start of this header). Almost always set to 0x8 (the size of this struct).
} NsoModStart; } NsoModStart;
NXDT_ASSERT(NsoModStart, 0x8);
/// This is essentially a replacement for the PT_DYNAMIC program header available in ELF binaries. /// This is essentially a replacement for the PT_DYNAMIC program header available in ELF binaries.
/// All offsets are signed 32-bit values relative to the start of this header. /// All offsets are signed 32-bit values relative to the start of this header.
/// This is usually placed at the start of the decompressed .text segment, right after a NsoModStart block. /// This is usually placed at the start of the decompressed .text segment, right after a NsoModStart block.
@ -106,6 +116,8 @@ typedef struct {
s32 module_object_offset; ///< Typically equal to bss_start_offset. s32 module_object_offset; ///< Typically equal to bss_start_offset.
} NsoModHeader; } NsoModHeader;
NXDT_ASSERT(NsoModHeader, 0x1C);
/// Placed at the start of the decompressed .rodata segment + 0x4. /// Placed at the start of the decompressed .rodata segment + 0x4.
/// If the 'name_length' element is greater than 0, 'name' will hold the module name. /// If the 'name_length' element is greater than 0, 'name' will hold the module name.
typedef struct { typedef struct {
@ -113,6 +125,8 @@ typedef struct {
char name[]; char name[];
} NsoModuleInfo; } NsoModuleInfo;
NXDT_ASSERT(NsoModuleInfo, 0x4);
typedef struct { typedef struct {
PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where this NSO is stored. PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where this NSO is stored.
PartitionFileSystemEntry *pfs_entry; ///< PartitionFileSystemEntry for this NSO in the Program NCA FS section #0. Used to read NSO data. PartitionFileSystemEntry *pfs_entry; ///< PartitionFileSystemEntry for this NSO in the Program NCA FS section #0. Used to read NSO data.
@ -145,8 +159,8 @@ NX_INLINE void nsoFreeContext(NsoContext *nso_ctx)
memset(nso_ctx, 0, sizeof(NsoContext)); memset(nso_ctx, 0, sizeof(NsoContext));
} }
#endif /* __NSO_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __NSO_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __PFS_H__ #ifndef __PFS_H__
#define __PFS_H__ #define __PFS_H__
#include "nca.h" #include "nca.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PFS0_MAGIC 0x50465330 /* "PFS0". */ #define PFS0_MAGIC 0x50465330 /* "PFS0". */
typedef struct { typedef struct {
@ -38,6 +38,8 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} PartitionFileSystemHeader; } PartitionFileSystemHeader;
NXDT_ASSERT(PartitionFileSystemHeader, 0x10);
typedef struct { typedef struct {
u64 offset; u64 offset;
u64 size; u64 size;
@ -45,6 +47,8 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} PartitionFileSystemEntry; } PartitionFileSystemEntry;
NXDT_ASSERT(PartitionFileSystemEntry, 0x18);
/// Used with Partition FS sections from NCAs. /// Used with Partition FS sections from NCAs.
typedef struct { typedef struct {
NcaFsSectionContext *nca_fs_ctx; ///< Used to read NCA FS section data. NcaFsSectionContext *nca_fs_ctx; ///< Used to read NCA FS section data.
@ -190,8 +194,8 @@ NX_INLINE char *pfsGetEntryNameByIndexFromFileContext(PartitionFileSystemFileCon
return (ctx->name_table + fs_entry->name_offset); return (ctx->name_table + fs_entry->name_offset);
} }
#endif /* __PFS_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __PFS_H__ */

View file

@ -20,16 +20,16 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __PROGRAM_INFO_H__ #ifndef __PROGRAM_INFO_H__
#define __PROGRAM_INFO_H__ #define __PROGRAM_INFO_H__
#include "npdm.h" #include "npdm.h"
#include "nso.h" #include "nso.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct { typedef struct {
NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which program data (NPDM / NSO) is retrieved. NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which program data (NPDM / NSO) is retrieved.
PartitionFileSystemContext pfs_ctx; ///< PartitionFileSystemContext for the Program NCA ExeFS, which is where program data (NPDM / NSO) is stored. PartitionFileSystemContext pfs_ctx; ///< PartitionFileSystemContext for the Program NCA ExeFS, which is where program data (NPDM / NSO) is stored.
@ -84,8 +84,8 @@ NX_INLINE void programInfoWriteNcaPatch(ProgramInfoContext *program_info_ctx, vo
if (program_info_ctx) npdmWriteNcaPatch(&(program_info_ctx->npdm_ctx), buf, buf_size, buf_offset); if (program_info_ctx) npdmWriteNcaPatch(&(program_info_ctx->npdm_ctx), buf, buf_size, buf_offset);
} }
#endif /* __PROGRAM_INFO_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __PROGRAM_INFO_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __ROMFS_H__ #ifndef __ROMFS_H__
#define __ROMFS_H__ #define __ROMFS_H__
#include "nca.h" #include "nca.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ROMFS_OLD_HEADER_SIZE 0x28 #define ROMFS_OLD_HEADER_SIZE 0x28
#define ROMFS_HEADER_SIZE 0x50 #define ROMFS_HEADER_SIZE 0x50
@ -48,6 +48,8 @@ typedef struct {
u32 body_offset; ///< File data body offset. u32 body_offset; ///< File data body offset.
} RomFileSystemInformationOld; } RomFileSystemInformationOld;
NXDT_ASSERT(RomFileSystemInformationOld, ROMFS_OLD_HEADER_SIZE);
/// Header used by NCA2/NCA3 RomFS sections. /// Header used by NCA2/NCA3 RomFS sections.
typedef struct { typedef struct {
u64 header_size; ///< Header size. Must be equal to ROMFS_HEADER_SIZE. u64 header_size; ///< Header size. Must be equal to ROMFS_HEADER_SIZE.
@ -62,6 +64,8 @@ typedef struct {
u64 body_offset; ///< File data body offset. u64 body_offset; ///< File data body offset.
} RomFileSystemInformation; } RomFileSystemInformation;
NXDT_ASSERT(RomFileSystemInformation, ROMFS_HEADER_SIZE);
/// Header union. /// Header union.
typedef struct { typedef struct {
union { union {
@ -73,6 +77,8 @@ typedef struct {
}; };
} RomFileSystemHeader; } RomFileSystemHeader;
NXDT_ASSERT(RomFileSystemHeader, ROMFS_HEADER_SIZE);
/// Directory entry. Always aligned to a 4-byte boundary past the directory name. /// Directory entry. Always aligned to a 4-byte boundary past the directory name.
typedef struct { typedef struct {
u32 parent_offset; ///< Parent directory offset. u32 parent_offset; ///< Parent directory offset.
@ -84,6 +90,8 @@ typedef struct {
char name[]; ///< Name (UTF-8). char name[]; ///< Name (UTF-8).
} RomFileSystemDirectoryEntry; } RomFileSystemDirectoryEntry;
NXDT_ASSERT(RomFileSystemDirectoryEntry, 0x18);
/// Directory entry. Always aligned to a 4-byte boundary past the file name. /// Directory entry. Always aligned to a 4-byte boundary past the file name.
typedef struct { typedef struct {
u32 parent_offset; ///< Parent directory offset. u32 parent_offset; ///< Parent directory offset.
@ -95,6 +103,8 @@ typedef struct {
char name[]; ///< Name (UTF-8). char name[]; ///< Name (UTF-8).
} RomFileSystemFileEntry; } RomFileSystemFileEntry;
NXDT_ASSERT(RomFileSystemFileEntry, 0x20);
typedef struct { typedef struct {
NcaFsSectionContext *nca_fs_ctx; ///< Used to read NCA FS section data. NcaFsSectionContext *nca_fs_ctx; ///< Used to read NCA FS section data.
u64 offset; ///< RomFS offset (relative to the start of the NCA FS section). u64 offset; ///< RomFS offset (relative to the start of the NCA FS section).
@ -203,8 +213,8 @@ NX_INLINE void romfsFreeFileEntryPatch(RomFileSystemFileEntryPatch *patch)
memset(patch, 0, sizeof(RomFileSystemFileEntryPatch)); memset(patch, 0, sizeof(RomFileSystemFileEntryPatch));
} }
#endif /* __ROMFS_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __ROMFS_H__ */

View file

@ -22,13 +22,13 @@
#pragma once #pragma once
#ifndef __RSA_H__
#define __RSA_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __RSA_H__
#define __RSA_H__
#define RSA2048_SIG_SIZE 0x100 #define RSA2048_SIG_SIZE 0x100
#define RSA2048_PUBKEY_SIZE RSA2048_SIG_SIZE #define RSA2048_PUBKEY_SIZE RSA2048_SIG_SIZE
@ -44,8 +44,8 @@ const u8 *rsa2048GetCustomPublicKey(void);
/// Performs RSA-2048-OAEP decryption and verification. Used to decrypt the titlekey block from tickets with personalized crypto. /// Performs RSA-2048-OAEP decryption and verification. Used to decrypt the titlekey block from tickets with personalized crypto.
bool rsa2048OaepDecryptAndVerify(void *dst, size_t dst_size, const void *signature, const void *modulus, const void *exponent, size_t exponent_size, const void *label_hash, size_t *out_size); bool rsa2048OaepDecryptAndVerify(void *dst, size_t dst_size, const void *signature, const void *modulus, const void *exponent, size_t exponent_size, const void *label_hash, size_t *out_size);
#endif /* __RSA_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __RSA_H__ */

View file

@ -21,15 +21,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __SAVE_H__ #ifndef __SAVE_H__
#define __SAVE_H__ #define __SAVE_H__
#include "fatfs/ff.h" #include "fatfs/ff.h"
#ifdef __cplusplus
extern "C" {
#endif
#define IVFC_MAX_LEVEL 6 #define IVFC_MAX_LEVEL 6
#define SAVE_HEADER_SIZE 0x4000 #define SAVE_HEADER_SIZE 0x4000
@ -106,6 +106,8 @@ typedef struct {
u8 _0x190[0x70]; u8 _0x190[0x70];
} fs_layout_t; } fs_layout_t;
NXDT_ASSERT(fs_layout_t, 0x200);
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
u64 offset; u64 offset;
@ -114,12 +116,16 @@ typedef struct {
} duplex_info_t; } duplex_info_t;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(duplex_info_t, 0x14);
typedef struct { typedef struct {
u32 magic; /* "DPFS". */ u32 magic; /* "DPFS". */
u32 version; u32 version;
duplex_info_t layers[3]; duplex_info_t layers[3];
} duplex_header_t; } duplex_header_t;
NXDT_ASSERT(duplex_header_t, 0x44);
typedef struct { typedef struct {
u32 version; u32 version;
u32 main_data_block_count; u32 main_data_block_count;
@ -127,6 +133,8 @@ typedef struct {
u32 _0x0C; u32 _0x0C;
} journal_map_header_t; } journal_map_header_t;
NXDT_ASSERT(journal_map_header_t, 0x10);
typedef struct { typedef struct {
u32 magic; /* "JNGL". */ u32 magic; /* "JNGL". */
u32 version; u32 version;
@ -135,6 +143,8 @@ typedef struct {
u64 block_size; u64 block_size;
} journal_header_t; } journal_header_t;
NXDT_ASSERT(journal_header_t, 0x20);
typedef struct { typedef struct {
u32 magic; /* "SAVE". */ u32 magic; /* "SAVE". */
u32 version; u32 version;
@ -142,6 +152,8 @@ typedef struct {
u64 block_size; u64 block_size;
} save_fs_header_t; } save_fs_header_t;
NXDT_ASSERT(save_fs_header_t, 0x18);
typedef struct { typedef struct {
u64 block_size; u64 block_size;
u64 allocation_table_offset; u64 allocation_table_offset;
@ -154,6 +166,8 @@ typedef struct {
u32 file_table_block; u32 file_table_block;
} fat_header_t; } fat_header_t;
NXDT_ASSERT(fat_header_t, 0x30);
typedef struct { typedef struct {
u32 magic; /* "RMAP". */ u32 magic; /* "RMAP". */
u32 version; u32 version;
@ -163,6 +177,8 @@ typedef struct {
u8 _0x14[0x2C]; u8 _0x14[0x2C];
} remap_header_t; } remap_header_t;
NXDT_ASSERT(remap_header_t, 0x40);
typedef struct remap_segment_ctx_t remap_segment_ctx_t; typedef struct remap_segment_ctx_t remap_segment_ctx_t;
typedef struct remap_entry_ctx_t remap_entry_ctx_t; typedef struct remap_entry_ctx_t remap_entry_ctx_t;
@ -232,6 +248,8 @@ typedef struct {
u64 commit_id; u64 commit_id;
} extra_data_t; } extra_data_t;
NXDT_ASSERT(extra_data_t, 0x70);
typedef struct { typedef struct {
u64 logical_offset; u64 logical_offset;
u64 hash_data_size; u64 hash_data_size;
@ -239,6 +257,8 @@ typedef struct {
u32 reserved; u32 reserved;
} ivfc_level_hdr_t; } ivfc_level_hdr_t;
NXDT_ASSERT(ivfc_level_hdr_t, 0x18);
typedef struct { typedef struct {
u32 magic; u32 magic;
u32 id; u32 id;
@ -248,6 +268,8 @@ typedef struct {
u8 salt_source[0x20]; u8 salt_source[0x20];
} ivfc_save_hdr_t; } ivfc_save_hdr_t;
NXDT_ASSERT(ivfc_save_hdr_t, 0xC0);
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
u8 cmac[0x10]; u8 cmac[0x10];
@ -270,6 +292,8 @@ typedef struct {
} save_header_t; } save_header_t;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(save_header_t, 0x4000);
typedef struct { typedef struct {
duplex_storage_ctx_t layers[2]; duplex_storage_ctx_t layers[2];
duplex_storage_ctx_t data_layer; duplex_storage_ctx_t data_layer;
@ -294,6 +318,8 @@ typedef struct {
u32 virtual_index; u32 virtual_index;
} journal_map_entry_t; } journal_map_entry_t;
NXDT_ASSERT(journal_map_entry_t, 0x8);
typedef struct { typedef struct {
journal_map_header_t *header; journal_map_header_t *header;
journal_map_entry_t *entries; journal_map_entry_t *entries;
@ -387,6 +413,8 @@ typedef struct {
} save_file_info_t; } save_file_info_t;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(save_file_info_t, 0x14);
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
u32 next_directory; u32 next_directory;
@ -395,6 +423,8 @@ typedef struct {
} save_find_position_t; } save_find_position_t;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(save_find_position_t, 0x14);
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
u32 next_sibling; u32 next_sibling;
@ -405,6 +435,8 @@ typedef struct {
} save_table_entry_t; } save_table_entry_t;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(save_table_entry_t, 0x18);
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
u32 parent; u32 parent;
@ -414,6 +446,8 @@ typedef struct {
} save_fs_list_entry_t; } save_fs_list_entry_t;
#pragma pack(pop) #pragma pack(pop)
NXDT_ASSERT(save_fs_list_entry_t, 0x60);
typedef struct { typedef struct {
u32 free_list_head_index; u32 free_list_head_index;
u32 used_list_head_index; u32 used_list_head_index;
@ -517,8 +551,8 @@ save_ctx_t *save_open_savefile(const char *path, u32 action);
void save_close_savefile(save_ctx_t *ctx); void save_close_savefile(save_ctx_t *ctx);
bool save_get_fat_storage_from_file_entry_by_path(save_ctx_t *ctx, const char *path, allocation_table_storage_ctx_t *out_fat_storage, u64 *out_file_entry_size); bool save_get_fat_storage_from_file_entry_by_path(save_ctx_t *ctx, const char *path, allocation_table_storage_ctx_t *out_fat_storage, u64 *out_file_entry_size);
#endif /* __SAVE_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __SAVE_H__ */

View file

@ -20,13 +20,13 @@
#pragma once #pragma once
#ifndef __SERVICES_H__
#define __SERVICES_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __SERVICES_H__
#define __SERVICES_H__
/* Hardware clocks expressed in MHz. */ /* Hardware clocks expressed in MHz. */
#define CPU_CLKRT_NORMAL 1020 #define CPU_CLKRT_NORMAL 1020
#define CPU_CLKRT_OVERCLOCKED 1785 #define CPU_CLKRT_OVERCLOCKED 1785
@ -53,8 +53,8 @@ void servicesChangeHardwareClockRates(u32 cpu_rate, u32 mem_rate);
/// Perfectly safe under development units. Not available in older Atmosphère releases. /// Perfectly safe under development units. Not available in older Atmosphère releases.
Result servicesHasService(bool *out, const char *name); Result servicesHasService(bool *out, const char *name);
#endif /* __SERVICES_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __SERVICES_H__ */

View file

@ -23,6 +23,10 @@
#ifndef __SIGNATURE_H__ #ifndef __SIGNATURE_H__
#define __SIGNATURE_H__ #define __SIGNATURE_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef enum { typedef enum {
SignatureType_Rsa4096Sha1 = 0x10000, SignatureType_Rsa4096Sha1 = 0x10000,
SignatureType_Rsa2048Sha1 = 0x10001, SignatureType_Rsa2048Sha1 = 0x10001,
@ -39,24 +43,32 @@ typedef struct {
u8 padding[0x3C]; u8 padding[0x3C];
} SignatureBlockRsa4096; } SignatureBlockRsa4096;
NXDT_ASSERT(SignatureBlockRsa4096, 0x240);
typedef struct { typedef struct {
u32 sig_type; ///< SignatureType_Rsa2048Sha1, SignatureType_Rsa2048Sha256. u32 sig_type; ///< SignatureType_Rsa2048Sha1, SignatureType_Rsa2048Sha256.
u8 signature[0x100]; u8 signature[0x100];
u8 padding[0x3C]; u8 padding[0x3C];
} SignatureBlockRsa2048; } SignatureBlockRsa2048;
NXDT_ASSERT(SignatureBlockRsa2048, 0x140);
typedef struct { typedef struct {
u32 sig_type; ///< SignatureType_Ecc480Sha1, SignatureType_Ecc480Sha256. u32 sig_type; ///< SignatureType_Ecc480Sha1, SignatureType_Ecc480Sha256.
u8 signature[0x3C]; u8 signature[0x3C];
u8 padding[0x40]; u8 padding[0x40];
} SignatureBlockEcc480; } SignatureBlockEcc480;
NXDT_ASSERT(SignatureBlockEcc480, 0x80);
typedef struct { typedef struct {
u32 sig_type; ///< SignatureType_Hmac160Sha1. u32 sig_type; ///< SignatureType_Hmac160Sha1.
u8 signature[0x14]; u8 signature[0x14];
u8 padding[0x28]; u8 padding[0x28];
} SignatureBlockHmac160; } SignatureBlockHmac160;
NXDT_ASSERT(SignatureBlockHmac160, 0x40);
/// Helper inline functions. /// Helper inline functions.
NX_INLINE u32 signatureGetSigType(void *buf, bool byteswap) NX_INLINE u32 signatureGetSigType(void *buf, bool byteswap)
@ -100,4 +112,8 @@ NX_INLINE void *signatureGetPayload(void *buf, bool big_endian_sig_type)
return (signatureIsValidSigType(sig_type) ? (void*)((u8*)buf + signatureGetBlockSize(sig_type)) : NULL); return (signatureIsValidSigType(sig_type) ? (void*)((u8*)buf + signatureGetBlockSize(sig_type)) : NULL);
} }
#ifdef __cplusplus
}
#endif
#endif /* __SIGNATURE_H__ */ #endif /* __SIGNATURE_H__ */

View file

@ -50,6 +50,8 @@ typedef struct {
u8 reserved[0x04]; u8 reserved[0x04];
} TikListEntry; } TikListEntry;
NXDT_ASSERT(TikListEntry, 0x20);
/// 9.x+ CTR key entry in ES .data segment. Used to store CTR key/IV data for encrypted volatile tickets in ticket.bin and/or encrypted entries in ticket_list.bin. /// 9.x+ CTR key entry in ES .data segment. Used to store CTR key/IV data for encrypted volatile tickets in ticket.bin and/or encrypted entries in ticket_list.bin.
/// This is always stored in pairs. The first entry holds the key/IV for the encrypted volatile ticket, while the second entry holds the key/IV for the encrypted entry in ticket_list.bin. /// This is always stored in pairs. The first entry holds the key/IV for the encrypted volatile ticket, while the second entry holds the key/IV for the encrypted entry in ticket_list.bin.
/// First index in this list is always 0, and it's aligned to ES_CTRKEY_ENTRY_ALIGNMENT. /// First index in this list is always 0, and it's aligned to ES_CTRKEY_ENTRY_ALIGNMENT.
@ -59,6 +61,8 @@ typedef struct {
u8 ctr[AES_BLOCK_SIZE]; ///< AES-128-CTR counter/IV. Always zeroed out. u8 ctr[AES_BLOCK_SIZE]; ///< AES-128-CTR counter/IV. Always zeroed out.
} TikEsCtrKeyEntry9x; } TikEsCtrKeyEntry9x;
NXDT_ASSERT(TikEsCtrKeyEntry9x, 0x24);
/// Lookup pattern for TikEsCtrKeyEntry9x. /// Lookup pattern for TikEsCtrKeyEntry9x.
typedef struct { typedef struct {
u32 idx1; ///< Always set to 0 (first entry). u32 idx1; ///< Always set to 0 (first entry).
@ -66,6 +70,8 @@ typedef struct {
u32 idx2; ///< Always set to 1 (second entry). u32 idx2; ///< Always set to 1 (second entry).
} TikEsCtrKeyPattern9x; } TikEsCtrKeyPattern9x;
NXDT_ASSERT(TikEsCtrKeyPattern9x, 0x28);
/// Used to parse the eTicket device key retrieved from PRODINFO via setcalGetEticketDeviceKey(). /// Used to parse the eTicket device key retrieved from PRODINFO via setcalGetEticketDeviceKey().
/// Everything after the AES CTR is encrypted. /// Everything after the AES CTR is encrypted.
typedef struct { typedef struct {
@ -78,6 +84,8 @@ typedef struct {
u8 ghash[0x10]; u8 ghash[0x10];
} TikEticketDeviceKeyData; } TikEticketDeviceKeyData;
NXDT_ASSERT(TikEticketDeviceKeyData, 0x240);
/* Global variables. */ /* Global variables. */
static SetCalRsa2048DeviceKey g_eTicketDeviceKey = {0}; static SetCalRsa2048DeviceKey g_eTicketDeviceKey = {0};
@ -380,7 +388,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik)
switch(tik_common_block->titlekey_type) switch(tik_common_block->titlekey_type)
{ {
case TikTitleKeyType_Common: case TikTitleKeyType_Common:
/* No titlekek crypto used. */ /* No console-specific crypto used. Copy titlekek-encrypted titlekey right away. */
memcpy(tik->enc_titlekey, tik_common_block->titlekey_block, 0x10); memcpy(tik->enc_titlekey, tik_common_block->titlekey_block, 0x10);
break; break;
case TikTitleKeyType_Personalized: case TikTitleKeyType_Personalized:
@ -393,7 +401,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik)
eticket_devkey = (TikEticketDeviceKeyData*)g_eTicketDeviceKey.key; eticket_devkey = (TikEticketDeviceKeyData*)g_eTicketDeviceKey.key;
/* Perform a RSA-OAEP decrypt operation to get the titlekey. */ /* Perform a RSA-OAEP decrypt operation to get the titlekek-encrypted titlekey. */
if (!rsa2048OaepDecryptAndVerify(out_keydata, 0x100, tik_common_block->titlekey_block, eticket_devkey->modulus, eticket_devkey->exponent, 0x100, g_nullHash, &out_keydata_size) || \ if (!rsa2048OaepDecryptAndVerify(out_keydata, 0x100, tik_common_block->titlekey_block, eticket_devkey->modulus, eticket_devkey->exponent, 0x100, g_nullHash, &out_keydata_size) || \
out_keydata_size < 0x10) out_keydata_size < 0x10)
{ {
@ -401,7 +409,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik)
return false; return false;
} }
/* Copy decrypted titlekey. */ /* Copy titlekek-encrypted titlekey. */
memcpy(tik->enc_titlekey, out_keydata, 0x10); memcpy(tik->enc_titlekey, out_keydata, 0x10);
break; break;
@ -589,7 +597,7 @@ static bool tikGetTicketEntryOffsetFromTicketList(save_ctx_t *save_ctx, u8 *buf,
if (!memcmp(entry->rights_id.c, id->c, sizeof(id->c))) if (!memcmp(entry->rights_id.c, id->c, sizeof(id->c)))
{ {
/* Jackpot. */ /* Jackpot. */
*out_offset = (entry_offset << 5); /* (entry_offset / 0x20) * 0x400 */ *out_offset = (entry_offset << 5); /* (entry_offset / sizeof(TikListEntry)) * SIGNED_TIK_MAX_SIZE */
success = true; success = true;
break; break;
} }

View file

@ -20,25 +20,27 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __TIK_H__ #ifndef __TIK_H__
#define __TIK_H__ #define __TIK_H__
#include "signature.h" #include "signature.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SIGNED_TIK_MAX_SIZE 0x400 /* Max ticket entry size in the ES ticket system savedata file. */ #define SIGNED_TIK_MAX_SIZE 0x400 /* Max ticket entry size in the ES ticket system savedata file. */
#define SIGNED_TIK_MIN_SIZE sizeof(TikSigHmac160) /* Assuming no ESV1/ESV2 records are available. */ #define SIGNED_TIK_MIN_SIZE sizeof(TikSigHmac160) /* Assuming no ESV1/ESV2 records are available. */
typedef enum { #define GENERATE_TIK_STRUCT(sigtype, tiksize) \
TikType_None = 0, \
TikType_SigRsa4096 = 1, typedef struct { \
TikType_SigRsa2048 = 2, SignatureBlock##sigtype sig_block; \
TikType_SigEcc480 = 3, TikCommonBlock tik_common_block; \
TikType_SigHmac160 = 4 u8 es_section_record_data[]; \
} TikType; } TikSig##sigtype; \
\
NXDT_ASSERT(TikSig##sigtype, tiksize);
typedef enum { typedef enum {
TikTitleKeyType_Common = 0, TikTitleKeyType_Common = 0,
@ -84,25 +86,7 @@ typedef struct {
u16 sect_hdr_entry_size; u16 sect_hdr_entry_size;
} TikCommonBlock; } TikCommonBlock;
typedef struct { NXDT_ASSERT(TikCommonBlock, 0x180);
SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using little endian byte order.
TikCommonBlock tik_common_block;
} TikSigRsa4096;
typedef struct {
SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using little endian byte order.
TikCommonBlock tik_common_block;
} TikSigRsa2048;
typedef struct {
SignatureBlockEcc480 sig_block; ///< sig_type field is stored using little endian byte order.
TikCommonBlock tik_common_block;
} TikSigEcc480;
typedef struct {
SignatureBlockHmac160 sig_block; ///< sig_type field is stored using little endian byte order.
TikCommonBlock tik_common_block;
} TikSigHmac160;
/// ESV1/ESV2 section records are placed right after the ticket data. These aren't available in TikTitleKeyType_Common tickets. /// ESV1/ESV2 section records are placed right after the ticket data. These aren't available in TikTitleKeyType_Common tickets.
/// These are only used if the sect_* fields from the common block are non-zero (other than 'sect_hdr_offset'). /// These are only used if the sect_* fields from the common block are non-zero (other than 'sect_hdr_offset').
@ -164,6 +148,21 @@ typedef struct {
u32 ref_id_attr; u32 ref_id_attr;
} TikESV1LimitedResourceRecord; } TikESV1LimitedResourceRecord;
/// All tickets generated below use a little endian sig_type field.
GENERATE_TIK_STRUCT(Rsa4096, 0x3C0); /// RSA-4096 signature.
GENERATE_TIK_STRUCT(Rsa2048, 0x2C0); /// RSA-2048 signature.
GENERATE_TIK_STRUCT(Ecc480, 0x200); /// ECC signature.
GENERATE_TIK_STRUCT(Hmac160, 0x1C0); /// HMAC signature.
/// Ticket type.
typedef enum {
TikType_None = 0,
TikType_SigRsa4096 = 1,
TikType_SigRsa2048 = 2,
TikType_SigEcc480 = 3,
TikType_SigHmac160 = 4
} TikType;
/// Used to store ticket type, size and raw data, as well as titlekey data. /// Used to store ticket type, size and raw data, as well as titlekey data.
typedef struct { typedef struct {
u8 type; ///< TikType. u8 type; ///< TikType.
@ -228,8 +227,8 @@ NX_INLINE bool tikIsPersonalizedTicket(Ticket *tik)
return (tik_common_block != NULL && tik_common_block->titlekey_type == TikTitleKeyType_Personalized); return (tik_common_block != NULL && tik_common_block->titlekey_type == TikTitleKeyType_Personalized);
} }
#endif /* __TIK_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __TIK_H__ */

View file

@ -20,13 +20,13 @@
#pragma once #pragma once
#ifndef __TITLE_H__
#define __TITLE_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __TITLE_H__
#define __TITLE_H__
#define TITLE_PATCH_TYPE_VALUE (u64)0x800 #define TITLE_PATCH_TYPE_VALUE (u64)0x800
#define TITLE_ADDONCONTENT_TYPE_VALUE (u64)0x1000 #define TITLE_ADDONCONTENT_TYPE_VALUE (u64)0x1000
@ -268,8 +268,8 @@ NX_INLINE u32 titleGetCountFromInfoBlock(TitleInfo *title_info)
return count; return count;
} }
#endif /* __TITLE_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __TITLE_H__ */

View file

@ -20,15 +20,15 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __UMS_H__ #ifndef __UMS_H__
#define __UMS_H__ #define __UMS_H__
#include <usbhsfs.h> #include <usbhsfs.h>
#ifdef __cplusplus
extern "C" {
#endif
/// Initializes the USB Mass Storage interface. /// Initializes the USB Mass Storage interface.
bool umsInitialize(void); bool umsInitialize(void);
@ -42,8 +42,8 @@ bool umsIsDeviceInfoUpdated(void);
/// Returns NULL if an error occurs. /// Returns NULL if an error occurs.
UsbHsFsDevice *umsGetDevices(u32 *out_count); UsbHsFsDevice *umsGetDevices(u32 *out_count);
#endif /* __UMS_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __UMS_H__ */

View file

@ -75,6 +75,8 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} UsbCommandHeader; } UsbCommandHeader;
NXDT_ASSERT(UsbCommandHeader, 0x10);
typedef struct { typedef struct {
u8 app_ver_major; u8 app_ver_major;
u8 app_ver_minor; u8 app_ver_minor;
@ -84,6 +86,8 @@ typedef struct {
u8 reserved[0x4]; u8 reserved[0x4];
} UsbCommandStartSession; } UsbCommandStartSession;
NXDT_ASSERT(UsbCommandStartSession, 0x10);
typedef struct { typedef struct {
u64 file_size; u64 file_size;
u32 filename_length; u32 filename_length;
@ -92,6 +96,8 @@ typedef struct {
u8 reserved_2[0xF]; u8 reserved_2[0xF];
} UsbCommandSendFileProperties; } UsbCommandSendFileProperties;
NXDT_ASSERT(UsbCommandSendFileProperties, 0x320);
typedef enum { typedef enum {
///< Expected response code. ///< Expected response code.
UsbStatusType_Success = 0, UsbStatusType_Success = 0,
@ -116,6 +122,8 @@ typedef struct {
u8 reserved[0x6]; u8 reserved[0x6];
} UsbStatus; } UsbStatus;
NXDT_ASSERT(UsbStatus, 0x10);
/// Imported from libusb, with some adjustments. /// Imported from libusb, with some adjustments.
enum usb_bos_type { enum usb_bos_type {
USB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1, USB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1,
@ -150,6 +158,8 @@ struct usb_bos_descriptor {
u8 bNumDeviceCaps; ///< The number of separate device capability descriptors in the BOS. u8 bNumDeviceCaps; ///< The number of separate device capability descriptors in the BOS.
} PACKED; } PACKED;
NXDT_ASSERT(struct usb_bos_descriptor, 0x5);
/// Imported from libusb, with some adjustments. /// Imported from libusb, with some adjustments.
struct usb_2_0_extension_descriptor { struct usb_2_0_extension_descriptor {
u8 bLength; u8 bLength;
@ -158,6 +168,8 @@ struct usb_2_0_extension_descriptor {
u32 bmAttributes; ///< usb_2_0_extension_attributes. u32 bmAttributes; ///< usb_2_0_extension_attributes.
} PACKED; } PACKED;
NXDT_ASSERT(struct usb_2_0_extension_descriptor, 0x7);
/// Imported from libusb, with some adjustments. /// Imported from libusb, with some adjustments.
struct usb_ss_usb_device_capability_descriptor { struct usb_ss_usb_device_capability_descriptor {
u8 bLength; u8 bLength;
@ -170,6 +182,8 @@ struct usb_ss_usb_device_capability_descriptor {
u16 bU2DevExitLat; ///< U2 Device Exit Latency. u16 bU2DevExitLat; ///< U2 Device Exit Latency.
} PACKED; } PACKED;
NXDT_ASSERT(struct usb_ss_usb_device_capability_descriptor, 0xA);
/* Global variables. */ /* Global variables. */
static RwLock g_usbDeviceLock = {0}; static RwLock g_usbDeviceLock = {0};

View file

@ -23,13 +23,13 @@
#pragma once #pragma once
#ifndef __USB_H__
#define __USB_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifndef __USB_H__
#define __USB_H__
#define USB_TRANSFER_BUFFER_SIZE 0x800000 /* 8 MiB. */ #define USB_TRANSFER_BUFFER_SIZE 0x800000 /* 8 MiB. */
/// Initializes the USB interface, input and output endpoints and allocates an internal transfer buffer. /// Initializes the USB interface, input and output endpoints and allocates an internal transfer buffer.
@ -73,8 +73,8 @@ NX_INLINE bool usbSendFilePropertiesCommon(u64 file_size, const char *filename)
return usbSendFileProperties(file_size, filename, 0); return usbSendFileProperties(file_size, filename, 0);
} }
#endif /* __USB_H__ */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __USB_H__ */

View file

@ -145,4 +145,4 @@ NX_INLINE void utilsSleep(u64 seconds)
} }
#endif #endif
#endif /* __UTILS_H__ */ #endif /* __UTILS_H__ */