Changes

3,624 bytes added ,  16 April
no edit summary
Line 1: Line 1: −
Known internally as "XCI" (NX Card Image), this is the format used for storing the contents of a Nintendo Switch Gamecard.  
+
This is the format used for storing the contents of a Nintendo Switch Gamecard.
   −
= Gamecard Header =
+
= Structure =
This header is 0x200 bytes and is located at offset 0 in the Gamecard.
+
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x1000
 +
| [[#CardKeyArea]]
 +
|-
 +
| 0x1000
 +
| 0x200
 +
| [[#CardHeader]]
 +
|-
 +
| 0x1200
 +
| 0x200
 +
| [11.0.0+] [[#NewCardHeader]]
 +
|-
 +
| 0x1400
 +
| 0x400
 +
| [11.0.0+] [[#NewCardHeaderCertArea]]
 +
|-
 +
| 0x1800
 +
| 0x6800
 +
| ReservedArea
 +
|-
 +
| 0x8000
 +
| 0x8000
 +
| [[#CertArea]]
 +
|-
 +
| 0x10000
 +
| Variable
 +
| [[#NormalArea]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#RomArea]]
 +
|-
 +
| Invalid
 +
| Invalid
 +
| BackupArea
 +
|}
 +
 
 +
== CardKeyArea ==
 +
This region cannot be read directly once written to the Gamecard. Therefore, it is hidden away during read/write operations on the raw Gamecard data.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x200
 +
| [[#InitialData]]
 +
|-
 +
| 0x200
 +
| 0xD00
 +
| [[#TitleKeyArea]]
 +
|-
 +
| 0xF00
 +
| 0x100
 +
| Reserved
 +
|}
 +
 
 +
=== InitialData ===
 +
This region is used for challenge–response authentication when changing to the Gamecard's secure mode.
 +
 
 +
[[Filesystem_services|FS]] calculates a SHA-256 hash over the whole 0x200 bytes and compares it with the hash stored at offset 0x160 in the [[#CardHeader]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| Package ID from [[#CardHeader]] at offset 0x110
 +
|-
 +
| 0x8
 +
| 0x8
 +
| Reserved
 +
|-
 +
| 0x10
 +
| 0x10
 +
| Challenge–response authentication data
 +
|-
 +
| 0x20
 +
| 0x10
 +
| Challenge–response authentication MAC
 +
|-
 +
| 0x30
 +
| 0xC
 +
| Challenge–response authentication Nonce
 +
|-
 +
| 0x3C
 +
| 0x1C4
 +
| Reserved (must be empty)
 +
|}
 +
 
 +
=== TitleKeyArea ===
 +
This region is stored encrypted and contains the title keys used by the [[#InitialData]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x8
 +
| TitleKey1
 +
|-
 +
| 0x8
 +
| 0x8
 +
| TitleKey2
 +
|-
 +
| 0x10
 +
| 0xCF0
 +
| Reserved
 +
|}
    +
== CardHeader ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 16: Line 138:  
| 0x100
 
| 0x100
 
| 0x4
 
| 0x4
| Magicnum "HEAD"
+
| Magic ("HEAD")
 
|-
 
|-
 
| 0x104
 
| 0x104
 
| 0x4
 
| 0x4
| Secure Area Start Address (in Media Units which are 0x200 bytes)
+
| RomAreaStartPageAddress (in Gamecard page units, which are 0x200 bytes)
 
|-
 
|-
 
| 0x108
 
| 0x108
 
| 0x4
 
| 0x4
| Backup Area Start Address (always 0xFFFFFFFF)
+
| BackupAreaStartPageAddress (always 0xFFFFFFFF)
 
|-
 
|-
 
| 0x10C
 
| 0x10C
 
| 0x1
 
| 0x1
| TitleKeyDec Index (high nibble) and KEK Index (low nibble)
+
| TitleKeyDecIndex (high nibble) and KekIndex (low nibble)
 
|-
 
|-
 
| 0x10D
 
| 0x10D
 
| 0x1
 
| 0x1
| Gamecard Size (0xFA = 1GB, 0xF8 = 2GB, 0xF0 = 4GB, 0xE0 = 8GB, 0xE1 = 16GB, 0xE2 = 32GB)
+
| [[#RomSize]]
 
|-
 
|-
 
| 0x10E
 
| 0x10E
 
| 0x1
 
| 0x1
| Gamecard Header Version
+
| CardHeaderVersion
 
|-
 
|-
 
| 0x10F
 
| 0x10F
 
| 0x1
 
| 0x1
| Gamecard Flags (bit0 = AutoBoot, bit1 = HistoryErase, bit2 = RepairTool)
+
| [[#Flags]]
 
|-
 
|-
 
| 0x110
 
| 0x110
 
| 0x8
 
| 0x8
| Package ID (used for challenge–response authentication)
+
| PackageId (used for challenge–response authentication)
 
|-
 
|-
 
| 0x118
 
| 0x118
| 0x8
+
| 0x4
| Valid Data End Address (in Media Units which are 0x200 bytes)
+
| ValidDataEndAddress (in Gamecard page units, which are 0x200 bytes)
 +
|-
 +
| 0x11C
 +
| 0x1
 +
| Reserved
 +
|-
 +
| 0x11D
 +
| 0x1
 +
| [18.0.0+] [[#Flags2]] ([1.0.0-17.0.1] Reserved)
 +
|-
 +
| 0x11E
 +
| 0x2
 +
| Reserved
 
|-
 
|-
 
| 0x120
 
| 0x120
 
| 0x10
 
| 0x10
| Gamecard Info IV (reversed)
+
| Iv (reversed)
 
|-
 
|-
 
| 0x130
 
| 0x130
 
| 0x8
 
| 0x8
| HFS0 partition offset
+
| PartitionFsHeaderAddress
 
|-
 
|-
 
| 0x138
 
| 0x138
 
| 0x8
 
| 0x8
| HFS0 header size
+
| PartitionFsHeaderSize
 
|-
 
|-
 
| 0x140
 
| 0x140
 
| 0x20
 
| 0x20
| SHA-256 hash of the [[#HFS0 Header|HFS0 Header]]
+
| PartitionFsHeaderHash (SHA-256 hash of the [[#PartitionFsHeader]])
 
|-
 
|-
 
| 0x160
 
| 0x160
 
| 0x20
 
| 0x20
| SHA-256 hash of the [[#Initial Data|Initial Data]]
+
| InitialDataHash (SHA-256 hash of the [[#InitialData]])
 
|-
 
|-
 
| 0x180
 
| 0x180
 
| 0x4
 
| 0x4
| Security Mode (0x01 = T1, 0x02 = T2)
+
| [[#SelSec]]
 
|-
 
|-
 
| 0x184
 
| 0x184
 
| 0x4
 
| 0x4
| T1 Key Index (always 2)
+
| SelT1Key (always 2)
 
|-
 
|-
 
| 0x188
 
| 0x188
 
| 0x4
 
| 0x4
| Key Index (always 0)
+
| SelKey (always 0)
 
|-
 
|-
 
| 0x18C
 
| 0x18C
 
| 0x4
 
| 0x4
| Normal Area End Address (in Media Units which are 0x200 bytes)
+
| LimArea (in Gamecard page units, which are 0x200 bytes)
 
|-
 
|-
 
| 0x190
 
| 0x190
 
| 0x70
 
| 0x70
| [[#Gamecard Info|Gamecard Info]] (AES-128-CBC encrypted)
+
| [[#CardHeaderEncryptedData]]
 +
|}
 +
 
 +
=== RomSize ===
 +
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardSize|GameCardSize]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0xFA
 +
| 1GB
 +
|-
 +
| 0xF8
 +
| 2GB
 +
|-
 +
| 0xF0
 +
| 4GB
 +
|-
 +
| 0xE0
 +
| 8GB
 +
|-
 +
| 0xE1
 +
| 16GB
 +
|-
 +
| 0xE2
 +
| 32GB
 +
|}
 +
 
 +
=== Flags ===
 +
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardAttribute|GameCardAttribute]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Bits
 +
! Description
 +
|-
 +
| 0
 +
| AutoBoot
 +
|-
 +
| 1
 +
| HistoryErase
 +
|-
 +
| 2
 +
| [4.0.0+] RepairTool
 +
|-
 +
| 3
 +
| [9.0.0+] DifferentRegionCupToTerraDevice
 +
|-
 +
| 4
 +
| [9.0.0+] DifferentRegionCupToGlobalDevice
 +
|-
 +
| 7
 +
| [11.0.0+] HasNewCardHeader
 
|}
 
|}
   −
== Gamecard Info ==
+
=== Flags2 ===
When decrypted, this 0x70 byte region is as follows:
+
[[Filesystem_services|FS]] retrieves this data as [[Filesystem_services#GameCardAttribute2|GameCardAttribute2]].
 +
 
 +
=== SelSec ===
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 1
 +
| T1
 +
|-
 +
| 2
 +
| T2
 +
|}
 +
 
 +
=== CardHeaderEncryptedData ===
 +
This region is stored encrypted (AES-128-CBC).
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 102: Line 306:  
| 0x0
 
| 0x0
 
| 0x8
 
| 0x8
| Firmware Version (0x00 = Development, 0x01 = Retail, 0x02 = Retail on 4.0.0+)
+
| [[#FwVersion]]
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0x4
 
| 0x4
| Access Control (0x00A10011 = 25MHz access, 0x00A10010 = 50MHz access)
+
| [[#AccCtrl1]]
 
|-
 
|-
 
| 0xC
 
| 0xC
 
| 0x4
 
| 0x4
| Read Time Wait1 (always 0x1388)
+
| Wait1TimeRead (always 0x1388)
 
|-
 
|-
 
| 0x10
 
| 0x10
 
| 0x4
 
| 0x4
| Read Time Wait2 (always 0)
+
| Wait2TimeRead (always 0)
 
|-
 
|-
 
| 0x14
 
| 0x14
 
| 0x4
 
| 0x4
| Write Time Wait1 (always 0)
+
| Wait1TimeWrite (always 0)
 
|-
 
|-
 
| 0x18
 
| 0x18
 
| 0x4
 
| 0x4
| Write Time Wait2 (always 0)
+
| Wait2TimeWrite (always 0)
 
|-
 
|-
 
| 0x1C
 
| 0x1C
 
| 0x4
 
| 0x4
| Firmware Mode
+
| FwMode (the current SdkAddonVersion)
 
|-
 
|-
 
| 0x20
 
| 0x20
 
| 0x4
 
| 0x4
| CUP Version
+
| UppVersion
 
|-
 
|-
 
| 0x24
 
| 0x24
| 0x4
+
| 0x1
| Empty
+
| [9.0.0+] [[#CompatibilityType]]
 +
|-
 +
| 0x25
 +
| 0x3
 +
| Reserved
 
|-
 
|-
 
| 0x28
 
| 0x28
 
| 0x8
 
| 0x8
| Update Partition Hash
+
| UppHash (SHA-256 hash of the [[#UpdatePartition]])
 
|-
 
|-
 
| 0x30
 
| 0x30
 
| 0x8
 
| 0x8
| CUP ID (always 0x0100000000000816, which is the title-listing data archive's title ID)
+
| UppId (always 0x0100000000000816)
 
|-
 
|-
 
| 0x38
 
| 0x38
 
| 0x38
 
| 0x38
| Empty
+
| Reserved
 
|}
 
|}
   −
= Gamecard Certificate =
+
==== FwVersion ====
This is the Gamecard's unique certificate and is located at offset 0x7000.
+
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0
 +
| Development
 +
|-
 +
| 1
 +
| Retail
 +
|-
 +
| 2
 +
| [4.0.0+] Retail
 +
|-
 +
| 3
 +
| [11.0.0+] Development
 +
|-
 +
| 4
 +
| [11.0.0+] Retail
 +
|-
 +
| 5
 +
| [12.0.0+] Retail
 +
|}
 +
 
 +
==== AccCtrl1 ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0x00A10011
 +
| 25MHz
 +
|-
 +
| 0x00A10010
 +
| 50MHz
 +
|}
   −
[[Filesystem_services|FS]] IDeviceOperator cmd 206 "GetGameCardDeviceCertificate" retrieves this data.
+
==== CompatibilityType ====
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value
 +
! Description
 +
|-
 +
| 0
 +
| Normal
 +
|-
 +
| 1
 +
| Terra
 +
|}
    +
== NewCardHeader ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 165: Line 420:  
|-
 
|-
 
| 0x100
 
| 0x100
 +
| 0x90
 +
|
 +
|-
 +
| 0x190
 +
| 0x70
 +
| [[#NewCardHeaderEncryptedData]]
 +
|}
 +
 +
=== NewCardHeaderEncryptedData ===
 +
This region is stored encrypted (AES-128-CBC).
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x40
 +
|
 +
|-
 +
| 0x40
 +
| 0x20
 +
| SHA-256 hash of the [[#CardHeader]]
 +
|-
 +
| 0x60
 +
| 0x10
 +
| Reserved
 +
|}
 +
 +
== NewCardHeaderCertArea ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x100
 +
| RSA-2048 PKCS #1 signature over the data from 0x100 to 0x300
 +
|-
 +
| 0x100
 +
| 0x30
 +
|
 +
|-
 +
| 0x130
 +
| 0x100
 +
| [[#NewCardHeader]] modulus
 +
|-
 +
| 0x230
 
| 0x4
 
| 0x4
| Magicnum "CERT"
+
| [[#NewCardHeader]] exponent
 +
|-
 +
| 0x234
 +
| 0x1CC
 +
|
 +
|}
 +
 
 +
== CertArea ==
 +
This is the Gamecard's unique certificate.
 +
 
 +
[[Filesystem_services|FS]] retrieves this data with [[Filesystem_services#GetGameCardDeviceCertificate|GetGameCardDeviceCertificate]].
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x100
 +
| RSA-2048 PKCS #1 signature over the data from 0x100 to 0x200
 +
|-
 +
| 0x100
 +
| 0x4
 +
| Magic ("CERT")
 
|-
 
|-
 
| 0x104
 
| 0x104
 
| 0x4
 
| 0x4
| Empty
+
| Version
 
|-
 
|-
 
| 0x108
 
| 0x108
 
| 0x1
 
| 0x1
| KEK Index
+
| KekIndex
 
|-
 
|-
 
| 0x109
 
| 0x109
 
| 0x7
 
| 0x7
| Empty
+
| Reserved
 
|-
 
|-
 
| 0x110
 
| 0x110
 
| 0x10
 
| 0x10
| Device ID
+
| T1CardDeviceId
 
|-
 
|-
 
| 0x120
 
| 0x120
 
| 0x10
 
| 0x10
| Unknown
+
| Iv
 
|-
 
|-
 
| 0x130
 
| 0x130
| 0xD0
+
| 0x10
| Encrypted data
+
| HwKey (encrypted)
 +
|-
 +
| 0x140
 +
| 0xC0
 +
| Reserved (encrypted)
 +
|-
 +
| 0x200
 +
| 0x7E00
 +
| Reserved
 
|}
 
|}
   −
The data between the Gamecard Certificate and the start of the HFS0 region is all 0xFF.
+
== NormalArea ==
 
+
This region contains all non-secure partitions of the Gamecard file system.
= Initial Data =
  −
This data is used for challenge–response authentication when changing to the Gamecard's secure mode.
  −
 
  −
[[Filesystem_services|FS]] calculates a SHA-256 hash over the whole 0x200 bytes and compares it with the hash stored at offset 0x160 in the [[#Gamecard Header|Gamecard Header]].
      
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 206: Line 539:  
! Description
 
! Description
 
|-
 
|-
| 0x0
+
| Variable
| 0x8
+
| Variable
| Package ID from [[#Gamecard Header|Gamecard Header]] at offset 0x110
+
| [[#PartitionFsHeader|RootPartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#PartitionFsHeader|UpdatePartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [[#UpdatePartition|UpdatePartition]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [4.0.0+] [[#PartitionFsHeader|LogoPartitionHeader]]
 +
|-
 +
| Variable
 +
| Variable
 +
| [4.0.0+] [[#LogoPartition|LogoPartition]]
 
|-
 
|-
| 0x8
+
| Variable
| 0x8
+
| Variable
| Empty
+
| [[#PartitionFsHeader|NormalPartitionHeader]]
 
|-
 
|-
| 0x10
+
| Variable
| 0x10
+
| Variable
| Challenge–response authentication data
+
| [[#NormalPartition|NormalPartition]]
 +
|}
 +
 
 +
=== UpdatePartition ===
 +
This partition contains .cnmt.nca + .nca files for the entire system update required to play the game. Launch day carts contain a full copy of 1.0 ncas, newer carts contain newer sysupdate NCAs etc.
 +
 
 +
=== NormalPartition ===
 +
This partition contains the .cnmt.nca and the game icondata nca. This is presumably for future compatibility so that if a future update changes the cryptographic protocol for the secure partition. Game icon data can still be shown in the home menu on old firmwares.
 +
 
 +
[4.0.0+] This partition is now empty.
 +
 
 +
=== LogoPartition ===
 +
[4.0.0+] This partition now contains the contents of the [[#NormalPartition]].
 +
 
 +
== RomArea ==
 +
This region contains all secure partitions of the Gamecard file system.
 +
 
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x20
+
! Offset
| 0x10
+
! Size
| Challenge–response authentication MAC
+
! Description
 
|-
 
|-
| 0x30
+
| Variable
| 0xC
+
| Variable
| Challenge–response authentication Nonce
+
| [[#PartitionFsHeader|SecurePartitionHeader]]
 
|-
 
|-
| 0x3C
+
| Variable
| 0x1C4
+
| Variable
| Reserved (must be empty)
+
| [[#SecurePartition|SecurePartition]]
 
|}
 
|}
   −
= HFS0 =
+
=== SecurePartition ===
 +
This partition contains an identical copy of the .cnmt.nca and game icondata nca, as well as all other ncas required for the game.
 +
 
 +
== PartitionFs ==
 
This is the Gamecard file system which starts with magicnum "HFS0".
 
This is the Gamecard file system which starts with magicnum "HFS0".
   −
== Header ==
+
=== PartitionFsHeader ===
The "SHA-256 File System" or "HFS0" starts at offset 0xF000 in the Gamecard. The first 0x200 bytes act as a global header and represent the root partition which points to the other partitions ("normal", "logo", "update" and "secure).
+
The "SHA-256 File System" or "HFS0" starts at offset 0x10000 in the Gamecard. The first 0x200 bytes act as a global header and represent the root partition which points to the other partitions ("normal", "logo", "update" and "secure").
   −
A hash for this header is stored at offset 0x140 in the [[#Gamecard Header|Gamecard Header]].
+
A hash for this header is stored at offset 0x140 in the [[#CardHeader]].
 
  −
== File System ==
  −
The actual file system is as follows (also valid for the root partition):
      
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 250: Line 616:  
| 0x0
 
| 0x0
 
| 0x4
 
| 0x4
| Magicnum "HFS0"
+
| Magic ("HFS0")
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Number of files
+
| FileCount
 
|-
 
|-
 
| 0x8
 
| 0x8
 
| 0x4
 
| 0x4
| Size of the string table
+
| StringTableSize
 
|-
 
|-
 
| 0xC
 
| 0xC
 
| 0x4
 
| 0x4
| Zero/Reserved
+
| Reserved
 
|-
 
|-
 
| 0x10
 
| 0x10
 
| X
 
| X
| File Entry Table
+
| [[#FileEntryTable]]
 
|-
 
|-
 
| 0x10 + X
 
| 0x10 + X
 
| Y
 
| Y
| String Table
+
| StringTable
 
|-
 
|-
 
| 0x10 + X + Y
 
| 0x10 + X + Y
 
| Z
 
| Z
| Raw File Data
+
| RawFileData
 
|}
 
|}
   −
Where File Entry Table consists of Number of Files FileEntries:
+
==== FileEntryTable ====
 
   
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 311: Line 676:     
The string table is 00-padded to align the start of raw filedata with a sector/media unit boundary (usually?).
 
The string table is 00-padded to align the start of raw filedata with a sector/media unit boundary (usually?).
  −
= Cartridge Layout =
  −
Observed gamecards contain three partitions: "update", "normal", and "secure".
  −
  −
The update partition (Gamecard partition 0 for fsp-srv cmd 31) contains .cnmt.nca + .nca files for the entire system update required to play the game. Launch day carts contain a full copy of 1.0 ncas, newer carts contain newer sysupdate NCAs etc.
  −
  −
The normal partition contains the .cnmt.nca and the game icondata nca. This is presumably for future compatibility so that if a future update changes the cryptographic protocol for the secure partition, Game icon data can still be shown in the home menu on old firmwares.
  −
  −
The secure partition contains an identical copy of the .cnmt.nca and game icondata nca, as well as all other ncas required for the game.
  −
  −
The entire rest of the Gamecard after the secure partition ends is all FF padding.
  −
  −
[4.0.0+] The "normal" partition is now empty and a new partition "logo" was added.