#pragma once #include #include #include namespace ntd { namespace n3ds { #pragma pack(push,8) /** * @struct NcsdCommonHeader * @brief NCSD header is used in both NAND storage and Gamecard Images */ struct NcsdCommonHeader { static const uint32_t kStructMagic = tc::bn::make_struct_magic_uint32("NCSD"); static const size_t kPartitionNum = 8; enum PartitionFsType { PartitionFsType_None = 0, PartitionFsType_Normal = 1, PartitionFsType_FIRM = 3, PartitionFsType_AGBSave = 4, }; enum PartitionCryptoType { PartitionCryptoType_None = 0x00, PartitionCryptoType_TWL = 0x01, PartitionCryptoType_CTR = 0x02, PartitionCryptoType_SNAKE = 0x03, }; enum MediaPlatform : byte_t { MediaPlatform_CTR = 0, MediaPlatform_SNAKE = 1, }; enum MediaType : byte_t { MediaType_InnerDevice = 0, MediaType_Card1 = 1, MediaType_Card2 = 2, MediaType_ExtendedDevice = 3, }; enum FlagIndex { FlagIndex_Platform = 4, FlagIndex_Type = 5, FlagIndex_BlockSizeLog = 6, }; struct NcsdFlags { tc::bn::pad<4> reserved; tc::bn::bitarray<1> media_platform; byte_t media_type; byte_t block_size_log; // this flag determines the block_size = 1 << (block_size_log + 9), alternatively this is always 0, and the blocksize is always 0x200 tc::bn::bitarray<1> reserved_07; // raw byte access byte_t& operator[](size_t index) { return ((byte_t*)this)[index]; } const byte_t& operator[](size_t index) const { return ((const byte_t*)this)[index]; } const byte_t* data() const { return ((const byte_t*)this); } const size_t size() const { return sizeof(uint64_t); } }; static_assert(sizeof(NcsdFlags) == 8, "NcsdFlags had incorrect size."); struct OffsetSize { tc::bn::le32 blk_offset; tc::bn::le32 blk_size; }; static_assert(sizeof(OffsetSize) == 8, "OffsetSize had incorrect size."); struct GameCardExtendedHeader { // 0x90 std::array, kPartitionNum> partition_id; // 0xD0 tc::bn::pad<0x30> reserved; }; struct NandExtendedHeader { // 0x90 tc::bn::pad<0x70> reserved; }; // 0x00 tc::bn::le32 struct_magic; // NCSD tc::bn::le32 image_blk_size; tc::bn::le64 title_id; // 0x10 std::array partition_fs_type; std::array partition_crypto_type; // 0x20 std::array partition_offsetsize; // 0x60 /* std::array extended_header_hash; // unused // 0x80 tc::bn::le32 additional_header_size; // unused tc::bn::le32 sector0_offset; // unused */ tc::bn::pad<0x28> reserved_0x60; // 0x88 NcsdFlags flags; // 0x90 union { GameCardExtendedHeader card_ext; NandExtendedHeader nand_ext; }; }; static_assert(sizeof(NcsdCommonHeader) == 0x100, "NcsdCommonHeader had incorrect size."); struct CciHeader { enum CardDevice : byte_t { CardDevice_Unspecified = 0, CardDevice_NorFlash = 1, CardDevice_None = 2, CardDevice_BT = 3, }; enum PartitionIndex : byte_t { PartitionIndex_Application = 0, PartitionIndex_Manual = 1, PartitionIndex_DlpChild = 2, PartitionIndex_SnakeCup = 6, PartitionIndex_CtrCup = 7, }; enum RomSize : uint32_t { RomSize_128MB = 0x40000, RomSize_256MB = 0x80000, RomSize_512MB = 0x100000, RomSize_1GB = 0x200000, RomSize_2GB = 0x400000, RomSize_4GB = 0x800000, }; enum NcsdFlagIndex { NcsdFlagIndex_BackupWriteWaitTime = 0, NcsdFlagIndex_BackupSecurityVersion = 1, NcsdFlagIndex_CardInfo = 2, NcsdFlagIndex_CardDevice = 3, NcsdFlagIndex_MediaPlatform = 4, NcsdFlagIndex_MediaType = 5, NcsdFlagIndex_MediaBlockSize = 6, NcsdFlagIndex_CardDevice_Deprecated = 7, }; enum CardType { CardType_S1 = 0, CardType_S2 = 1, }; enum CryptoType { CryptoType_Secure0 = 0, // Secure initial data key (keyX bootrom, keyY initial data seed) (used in production ROMs) CryptoType_Secure1 = 1, // Secure initial data key (keyX bootrom, keyY initial data seed) (used in production ROMs) CryptoType_Secure2 = 2, // Secure initial data key (keyX bootrom, keyY initial data seed) (used in production ROMs) CryptoType_FixedKey = 3, // Zeros initial data key (used in non-HSM enviroments like development) }; struct CardInfo { struct Flag { byte_t reserved : 5; byte_t card_type : 1; // see CardType byte_t crypto_type : 2; // see CryptoType }; tc::bn::le32 writable_region; // offset in blocks tc::bn::pad<3> padding; Flag flag; tc::bn::pad<0xf8> reserved; }; static_assert(sizeof(CardInfo) == 0x100, "CardInfo had incorrect size."); struct MasteringMetadata { tc::bn::le64 media_size_used; tc::bn::pad<0x8> padding0; tc::bn::le16 title_version; tc::bn::le16 card_revision; tc::bn::pad<0xc> padding1; tc::bn::le64 cver_title_id; tc::bn::le16 cver_title_version; tc::bn::pad<0x6> padding2; tc::bn::pad<0xd0> reserved; }; static_assert(sizeof(MasteringMetadata) == 0x100, "MasteringMetadata had incorrect size."); struct InitialData { std::array key_source; std::array encrypted_title_key; std::array mac; std::array nonce; tc::bn::pad<4> padding; tc::bn::pad<0xc0> reserved; }; static_assert(sizeof(InitialData) == 0x100, "InitialData had incorrect size."); struct CardDeviceInfo { tc::bn::pad<0x200> card_device_reserved_0; std::array title_key; tc::bn::pad<0xf0> card_device_reserved_1; }; static_assert(sizeof(InitialData) == 0x100, "InitialData had incorrect size."); public: // 0x0000 - 0x00ff: RSA2048-PKCS1-SHA2-256 over 0x0100-0x01ff std::array signature; // 0x0100 - 0x01ff: NcsdCommonHeader NcsdCommonHeader ncsd_header; // 0x0200 - 0x02ff: CardInfo CardInfo card_info; // 0x0300 - 0x03ff: Mastering metadata MasteringMetadata mastering_info; // 0x0400 - 0x0fff: Reserved tc::bn::pad<0xc00> reserved_00; // 0x1000 - 0x10ff: Initial Data InitialData initial_data; // 0x1100 - 0x11ff: Partition0 NcchCommonHeader NcchCommonHeader ncch_header; // 0x1200 - 0x14ff: Contains decrypted titlekey for programming cards CardDeviceInfo card_device_info; // 0x1500 - 0x3fff: Reserved tc::bn::pad<0x2B00> reserved_01; }; static_assert(sizeof(CciHeader) == 0x4000, "CciHeader had incorrect size."); #pragma pack(pop) }} // namespace ntd::n3ds