Difference between revisions of "Lotus3"
(8 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
= Protocol = | = Protocol = | ||
− | All communication is done using | + | All communication is done using custom MMC_SEND_MANUFACTURER commands. |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Value |
− | ! | + | ! Description |
|- | |- | ||
| 60 | | 60 | ||
− | | [[#WriteOperation]] | + | | [[#WriteOperation|WriteOperation]] |
|- | |- | ||
| 61 | | 61 | ||
− | | [[#FinishOperation]] | + | | [[#FinishOperation|FinishOperation]] |
|- | |- | ||
| 62 | | 62 | ||
− | | [[#Sleep]] | + | | [[#Sleep|Sleep]] |
|- | |- | ||
| 63 | | 63 | ||
− | | [[#UpdateKey]] | + | | [[#UpdateKey|UpdateKey]] |
|} | |} | ||
== WriteOperation == | == WriteOperation == | ||
− | + | Sends a Gamecard ASIC [[#AsicOperation|operation]]. | |
+ | |||
+ | == FinishOperation == | ||
+ | Returns the status of a completed Gamecard ASIC operation. | ||
+ | |||
+ | == Sleep == | ||
+ | Puts the Gamecard ASIC in sleep mode. | ||
− | === | + | == UpdateKey == |
+ | Tells the Gamecard ASIC to generate new random key data. | ||
+ | |||
+ | = AsicOperation = | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 36: | Line 45: | ||
| 0x0 | | 0x0 | ||
| 0x1 | | 0x1 | ||
− | | | + | | [[#OperationId|OperationId]] |
|- | |- | ||
| 0x1 | | 0x1 | ||
| 0x1F | | 0x1F | ||
− | | | + | | OperationData |
|- | |- | ||
| 0x20 | | 0x20 | ||
| 0x20 | | 0x20 | ||
− | | | + | | CvValue (secure mode only) |
|} | |} | ||
− | == | + | == OperationId == |
− | + | The Gamecard ASIC supports a total of 20 operation commands. These commands are passed to the ASIC using the [[#WriteOperation|WriteOperation]] MMC command. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | The Gamecard ASIC supports a total of 20 operation commands. These commands are passed to the ASIC using the [[#WriteOperation]] MMC command. | ||
− | Additional data buffers are then read/written using standard MMC read/write commands. | + | Additional data buffers are then read/written as pages of 0x200 bytes each, using standard MMC read/write commands. |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Value |
− | ! | + | ! Description |
|- | |- | ||
| 0x01 | | 0x01 | ||
− | | [[#SendFirmware]] | + | | [[#SendFirmware|SendFirmware]] |
|- | |- | ||
| 0x02 | | 0x02 | ||
− | | [[#ReceiveCertificate]] | + | | [[#ReceiveCertificate|ReceiveCertificate]] |
|- | |- | ||
| 0x03 | | 0x03 | ||
− | | [[#SendSocCertificate]] | + | | [[#SendSocCertificate|SendSocCertificate]] |
|- | |- | ||
| 0x04 | | 0x04 | ||
− | | [[#ReceiveRandomValue]] | + | | [[#ReceiveRandomValue|ReceiveRandomValue]] |
|- | |- | ||
| 0x05 | | 0x05 | ||
− | | [[#SendRandomValue]] | + | | [[#SendRandomValue|SendRandomValue]] |
|- | |- | ||
| 0x06 | | 0x06 | ||
− | | [[#ReceiveDeviceChallenge]] | + | | [[#ReceiveDeviceChallenge|ReceiveDeviceChallenge]] |
|- | |- | ||
| 0x07 | | 0x07 | ||
− | | [[#RespondDeviceChallenge]] | + | | [[#RespondDeviceChallenge|RespondDeviceChallenge]] |
|- | |- | ||
| 0x08 | | 0x08 | ||
− | | [[#SendHostChallenge]] | + | | [[#SendHostChallenge|SendHostChallenge]] |
|- | |- | ||
| 0x09 | | 0x09 | ||
− | | [[#ReceiveChallengeResponse]] | + | | [[#ReceiveChallengeResponse|ReceiveChallengeResponse]] |
|- | |- | ||
| 0x0A | | 0x0A | ||
− | | [[#ChangeModeToSecure]] | + | | [[#ChangeModeToSecure|ChangeModeToSecure]] |
|- | |- | ||
| 0x0B | | 0x0B | ||
− | | [[#WriteRegister]] | + | | [[#WriteRegister|WriteRegister]] |
|- | |- | ||
| 0x0C | | 0x0C | ||
− | | [[#ReadRegister]] | + | | [[#ReadRegister|ReadRegister]] |
|- | |- | ||
| 0x0D | | 0x0D | ||
− | | [[#ChangeGcModeToDebug]] | + | | [[#ChangeGcModeToDebug|ChangeGcModeToDebug]] |
|- | |- | ||
| 0x0E | | 0x0E | ||
− | | [[#GetCardHeader]] | + | | [[#GetCardHeader|GetCardHeader]] |
|- | |- | ||
| 0x0F | | 0x0F | ||
− | | [[#ChangeGcModeToSecure]] | + | | [[#ChangeGcModeToSecure|ChangeGcModeToSecure]] |
|- | |- | ||
| 0x10 | | 0x10 | ||
− | | [[#SendCardCommand]] | + | | [[#SendCardCommand|SendCardCommand]] |
|- | |- | ||
| 0x11 | | 0x11 | ||
− | | [[#EnableCardBus]] | + | | [[#EnableCardBus|EnableCardBus]] |
|- | |- | ||
| 0x12 | | 0x12 | ||
− | | [[#ExchangeRandomValuesInSecureMode]] | + | | [[#ExchangeRandomValuesInSecureMode|ExchangeRandomValuesInSecureMode]] |
|- | |- | ||
| 0x13 | | 0x13 | ||
− | | [[#ReadRmaInformation]] | + | | [[#ReadRmaInformation|ReadRmaInformation]] |
|- | |- | ||
| 0x14 | | 0x14 | ||
− | | [9.0.0+] [[#ChallengeCardExistence]] | + | | [9.0.0+] [[#ChallengeCardExistence|ChallengeCardExistence]] |
|} | |} | ||
− | == SendFirmware == | + | === SendFirmware === |
− | Signals the Gamecard ASIC to receive | + | Signals the Gamecard ASIC to receive the [[#AsicFirmware|firmware]]. |
− | + | This is the only operation handled by the Gamecard ASIC's bootrom. | |
− | |||
− | == | + | === ReceiveCertificate === |
− | Signals the Gamecard ASIC to | + | Signals the Gamecard ASIC to send the ASIC's certificate. |
− | == | + | === SendSocCertificate === |
− | Signals the Gamecard ASIC to | + | Signals the Gamecard ASIC to receive the certificate from [[Settings_services#GetGameCardCertificate|GetGameCardCertificate]]. |
− | == | + | === ReceiveRandomValue === |
− | Signals the Gamecard ASIC to | + | Signals the Gamecard ASIC to send a RSA-OAEP encrypted message to be decrypted by the host library. |
− | + | The decrypted message will be used to generate a common AES-128 (CBC and CTR) key and IV/CTR shared between the ASIC and the host library. | |
− | |||
− | == | + | === SendRandomValue === |
− | Signals the Gamecard ASIC to receive a | + | Signals the Gamecard ASIC to receive a RSA-OAEP encrypted message to be decrypted by the ASIC. |
− | + | The decrypted message will be used to generate a common AES-128 (CBC and CTR) key and IV/CTR shared between the ASIC and the host library. | |
− | |||
− | == | + | === ReceiveDeviceChallenge === |
− | Signals the Gamecard ASIC to send | + | Signals the Gamecard ASIC to send AES-128-CBC encrypted authentication data to be decrypted and hashed by the host library. |
− | == | + | === RespondDeviceChallenge === |
− | Signals the Gamecard ASIC to | + | Signals the Gamecard ASIC to receive the AES-128-CBC encrypted hash of the ASIC authentication data. |
− | == | + | === SendHostChallenge === |
− | Signals the Gamecard ASIC to | + | Signals the Gamecard ASIC to receive AES-128-CBC encrypted authentication data to be decrypted and hashed by the ASIC. |
− | + | === ReceiveChallengeResponse === | |
− | + | Signals the Gamecard ASIC to send the AES-128-CBC encrypted hash of the library authentication data. | |
− | + | ||
− | + | === ChangeModeToSecure === | |
− | + | Signals the Gamecard ASIC to enter secure mode. | |
− | + | ||
− | + | In secure mode, all communication with the Gamecard ASIC must be AES-128-CTR encrypted. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | + | === WriteRegister === |
− | Signals the Gamecard ASIC to | + | Signals the Gamecard ASIC to write an internal register. |
+ | [[#AsicOperation|OperationData]] becomes: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 197: | Line 176: | ||
|- | |- | ||
| 0x0 | | 0x0 | ||
− | | | + | | 0x3 |
− | | | + | | Reserved |
|- | |- | ||
+ | | 0x3 | ||
| 0x4 | | 0x4 | ||
− | | | + | | RegisterAddress |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
+ | | 0x7 | ||
| 0x18 | | 0x18 | ||
− | | | + | | Reserved |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | + | RegisterValue is passed in a data page. | |
− | |||
− | == | + | === ReadRegister === |
− | Signals the Gamecard ASIC to send | + | Signals the Gamecard ASIC to send the contents of its [[#AsicRegisters|registers]]. |
− | + | === ChangeGcModeToDebug === | |
− | + | Signals the Gamecard ASIC to change into debug mode and send information on the current Gamecard. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == | + | === GetCardHeader === |
− | Signals the Gamecard ASIC to send | + | Signals the Gamecard ASIC to send the current Gamecard's [[#CardHeader|header]]. |
− | + | === ChangeGcModeToSecure === | |
− | + | Signals the Gamecard ASIC to enable secure communication with the Gamecard and return its [[#CardKeyArea|key area]]. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | == SendCardCommand == | + | === SendCardCommand === |
− | Signals the Gamecard ASIC to relay | + | Signals the Gamecard ASIC to relay commands to the Gamecard. |
+ | [[#AsicOperation|OperationData]] becomes: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 307: | Line 214: | ||
| 0x0 | | 0x0 | ||
| 0x1 | | 0x1 | ||
− | | | + | | PageSize |
|- | |- | ||
| 0x1 | | 0x1 | ||
| 0x1 | | 0x1 | ||
− | | | + | | Direction (0 = Read, 1 = Write) |
|- | |- | ||
| 0x2 | | 0x2 | ||
| 0x1 | | 0x1 | ||
− | | | + | | Reserved |
|- | |- | ||
| 0x3 | | 0x3 | ||
− | |||
− | |||
− | |||
| 0x4 | | 0x4 | ||
− | | | + | | PageNumber |
− | |||
|- | |- | ||
− | | | + | | 0x7 |
− | | | + | | 0x10 |
− | | | + | | [[#CardCommand|CardCommand]] |
|- | |- | ||
− | |||
| 0x17 | | 0x17 | ||
− | | | + | | 0x8 |
− | | | + | | Reserved |
− | |||
− | |||
− | |||
|} | |} | ||
− | == EnableCardBus == | + | === EnableCardBus === |
− | Signals the Gamecard ASIC to enable the | + | Signals the Gamecard ASIC to enable the Gamecard's bus line. |
− | == ExchangeRandomValuesInSecureMode == | + | === ExchangeRandomValuesInSecureMode === |
− | Signals the Gamecard ASIC to exchange random authentication values with the current Gamecard | + | Signals the Gamecard ASIC to exchange random authentication values with the current Gamecard. |
+ | [[#AsicOperation|OperationData]] becomes: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 351: | Line 251: | ||
|- | |- | ||
| 0x0 | | 0x0 | ||
− | |||
− | |||
− | |||
− | |||
| 0x1F | | 0x1F | ||
− | | | + | | RandomValues |
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | + | The Gamecard's response is returned in a data page. | |
− | |||
− | == | + | === ReadRmaInformation === |
− | Signals the Gamecard ASIC to | + | Signals the Gamecard ASIC to send information on the Gamecard ASIC. This is called by [[Filesystem_services#IDeviceOperator|GetGameCardAsicInfo]]. |
+ | === ChallengeCardExistence === | ||
+ | Signals the Gamecard ASIC to exchange random values with the current Gamecard. | ||
+ | |||
+ | [[#AsicOperation|OperationData]] becomes: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 376: | Line 271: | ||
|- | |- | ||
| 0x0 | | 0x0 | ||
− | |||
− | |||
− | |||
− | |||
| 0x1F | | 0x1F | ||
− | | | + | | RandomValues |
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | + | The Gamecard's response is returned in a data page. | |
− | |||
− | |||
− | |||
+ | = AsicRegisters = | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
+ | ! Description | ||
+ | |- | ||
+ | | 0x0 | ||
+ | | 0x4 | ||
+ | | Lotus3Status | ||
|- | |- | ||
− | | | + | | 0x4 |
− | | [[# | + | | 0x4 |
+ | | [[XCI#AccCtrl1|AccCtrl1]] | ||
|- | |- | ||
− | | | + | | 0x8 |
− | | | + | | 0x4 |
+ | | Wait1TimeRead | ||
|- | |- | ||
− | | | + | | 0xC |
− | | | + | | 0x4 |
+ | | Wait2TimeRead | ||
|- | |- | ||
− | | | + | | 0x10 |
− | | | + | | 0x4 |
+ | | Wait1TimeWrite | ||
|- | |- | ||
− | | | + | | 0x14 |
− | | | + | | 0x4 |
+ | | Wait2TimeWrite | ||
|- | |- | ||
| 0x18 | | 0x18 | ||
− | | | + | | 0x4 |
+ | | PageRemainder | ||
|- | |- | ||
− | | | + | | 0x1C |
− | | | + | | 0x4 |
+ | | LatencyTime | ||
|- | |- | ||
| 0x20 | | 0x20 | ||
− | | | + | | 0x4 |
+ | | LimArea | ||
|- | |- | ||
− | | | + | | 0x24 |
− | | | + | | 0x4 |
+ | | CupVersion | ||
|- | |- | ||
| 0x28 | | 0x28 | ||
− | | | + | | 0x4 |
+ | | Lotus3Version | ||
|- | |- | ||
− | | | + | | 0x2C |
− | | | + | | 0x4 |
− | + | | Standby2 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | | | ||
|} | |} | ||
− | == | + | = CardHeader = |
− | |||
− | |||
− | |||
− | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 477: | Line 341: | ||
|- | |- | ||
| 0x0 | | 0x0 | ||
− | | | + | | 0x4 |
− | | | + | | CupVersion |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
| 0x4 | | 0x4 | ||
| 0x4 | | 0x4 | ||
− | | | + | | [[Filesystem_services#CardId1|CardId1]] |
|- | |- | ||
| 0x8 | | 0x8 | ||
− | | | + | | 0x100 |
− | | | + | | [[XCI#CardHeader|CardHeader]] (without the signature) |
|- | |- | ||
− | | | + | | 0x108 |
− | | | + | | 0xD8 |
− | | | + | | Reserved |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
+ | | 0x1E0 | ||
| 0x20 | | 0x20 | ||
− | | | + | | [11.0.0+] SHA-256 hash of the data from 0 to 0x1E0 ([1.0.0-10.2.0] Reserved) |
− | |||
|} | |} | ||
− | == | + | = CardKeyArea = |
− | |||
− | |||
− | |||
− | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 533: | Line 369: | ||
|- | |- | ||
| 0x0 | | 0x0 | ||
− | | | + | | 0x4 |
− | | | + | | SecurityLevel |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
| 0x4 | | 0x4 | ||
| 0x4 | | 0x4 | ||
− | | | + | | Lotus3Status |
|- | |- | ||
| 0x8 | | 0x8 | ||
− | | | + | | 0x4 |
− | | | + | | [[Filesystem_services#CardId1|CardId1]] |
|- | |- | ||
− | | | + | | 0xC |
| 0x4 | | 0x4 | ||
− | | | + | | [[Filesystem_services#CardId2|CardId2]] |
+ | |- | ||
+ | | 0x10 | ||
+ | | 0x40 | ||
+ | | [[#CardUid|CardUid]] | ||
|- | |- | ||
− | | | + | | 0x50 |
− | | | + | | 0x1B0 |
− | | | + | | Reserved |
|- | |- | ||
− | | | + | | 0x200 |
− | | | + | | 0x200 |
− | | | + | | [[XCI#CertArea|CertArea]] |
|- | |- | ||
− | | | + | | 0x400 |
− | | | + | | 0x200 |
− | | | + | | Reserved |
|- | |- | ||
− | | | + | | 0x600 |
− | | | + | | 0x200 |
− | | | + | | [[XCI#InitialData|InitialData]] |
|} | |} | ||
− | + | [11.0.0+] This is now: | |
− | |||
− | |||
− | |||
− | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 589: | Line 413: | ||
|- | |- | ||
| 0x0 | | 0x0 | ||
− | | | + | | 0x4 |
− | | | + | | SecurityLevel |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
| 0x4 | | 0x4 | ||
| 0x4 | | 0x4 | ||
− | | | + | | Lotus3Status |
|- | |- | ||
| 0x8 | | 0x8 | ||
− | | | + | | 0x4 |
− | | | + | | [[Filesystem_services#CardId1|CardId1]] |
|- | |- | ||
− | | | + | | 0xC |
| 0x4 | | 0x4 | ||
− | | | + | | [[Filesystem_services#CardId2|CardId2]] |
|- | |- | ||
− | | | + | | 0x10 |
− | | | + | | 0x40 |
− | | | + | | [[#CardUid|CardUid]] |
|- | |- | ||
− | | | + | | 0x50 |
− | | | + | | 0x1B0 |
− | | | + | | Reserved |
|- | |- | ||
− | | | + | | 0x200 |
− | | | + | | 0x200 |
− | | | + | | [[XCI#CertArea|CertArea]] |
|- | |- | ||
− | | | + | | 0x400 |
− | | | + | | 0x200 |
− | | | + | | [[XCI#InitialData|InitialData]] |
|} | |} | ||
− | == | + | = CardUid = |
− | |||
− | |||
− | |||
− | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 646: | Line 454: | ||
| 0x0 | | 0x0 | ||
| 0x1 | | 0x1 | ||
− | | | + | | [[#MakerId|MakerId]] |
|- | |- | ||
| 0x1 | | 0x1 | ||
| 0x1 | | 0x1 | ||
− | | | + | | |
|- | |- | ||
| 0x2 | | 0x2 | ||
| 0x1 | | 0x1 | ||
− | | | + | | |
|- | |- | ||
| 0x3 | | 0x3 | ||
+ | | 0xD | ||
+ | | [[#UniqueData|UniqueData]] | ||
+ | |- | ||
+ | | 0x10 | ||
| 0x1 | | 0x1 | ||
− | | | + | | Reserved (always 0) |
|- | |- | ||
− | | | + | | 0x11 |
− | | | + | | 0xB |
− | | | + | | Reserved (always all 0xFF) |
|- | |- | ||
− | | | + | | 0x1C |
− | |||
− | |||
− | |||
− | |||
| 0x4 | | 0x4 | ||
− | | | + | | [[#CardId1Mirror|CardId1Mirror]] |
− | | | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
| 0x20 | | 0x20 | ||
| 0x20 | | 0x20 | ||
− | | | + | | Hash |
|} | |} | ||
− | == | + | == MakerId == |
− | |||
− | |||
− | |||
− | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Value |
− | |||
! Description | ! Description | ||
|- | |- | ||
− | | | + | | 0 |
− | | | + | | MegaChips (Macronix) |
− | |||
|- | |- | ||
− | | | + | | 1 |
− | | | + | | Lapis |
− | |||
|- | |- | ||
− | | | + | | 2 |
− | | | + | | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | == | + | == UniqueData == |
− | + | While presumed to be random, this field actually has some degree of determinism depending on the [[#MakerId|MakerId]]. | |
− | |||
− | |||
+ | MakerId 0: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 750: | Line 513: | ||
| 0x0 | | 0x0 | ||
| 0x1 | | 0x1 | ||
− | | | + | | Type (4 = [[Filesystem_services#MemoryType|T1RomLate]], 8 = [[Filesystem_services#MemoryType|T1RomFast]]) |
|- | |- | ||
| 0x1 | | 0x1 | ||
| 0x1 | | 0x1 | ||
− | | | + | | Line (0x21 for [[Filesystem_services#MemoryType|T1RomLate]], incrementing value for [[Filesystem_services#MemoryType|T1RomFast]]) |
|- | |- | ||
| 0x2 | | 0x2 | ||
− | |||
− | |||
− | |||
| 0x3 | | 0x3 | ||
− | | | + | | Id |
− | |||
|- | |- | ||
− | | | + | | 0x5 |
− | | | + | | 0x2 |
− | | | + | | X (16-bit coordinate?) |
|- | |- | ||
− | | | + | | 0x7 |
− | | | + | | 0x2 |
− | | | + | | Y (16-bit coordinate?) |
|- | |- | ||
| 0x9 | | 0x9 | ||
| 0x4 | | 0x4 | ||
− | | | + | | Random |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | + | MakerId 1: | |
− | |||
− | |||
− | |||
− | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 801: | Line 544: | ||
|- | |- | ||
| 0x0 | | 0x0 | ||
− | | | + | | 0x2 |
− | | | + | | Line (incrementing value) |
|- | |- | ||
− | | | + | | 0x2 |
− | | | + | | 0x3 |
− | | | + | | Id |
|- | |- | ||
− | | | + | | 0x5 |
| 0x1 | | 0x1 | ||
− | | | + | | |
|- | |- | ||
− | | | + | | 0x6 |
| 0x1 | | 0x1 | ||
− | | | + | | Version (0 or 1) |
|- | |- | ||
− | | | + | | 0x7 |
− | | | + | | 0x2 |
− | | | + | | |
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
| 0x9 | | 0x9 | ||
| 0x4 | | 0x4 | ||
− | | | + | | Random |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | + | MakerId 2: | |
− | |||
− | |||
− | |||
− | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 857: | Line 576: | ||
|- | |- | ||
| 0x0 | | 0x0 | ||
− | | | + | | 0x4 |
− | | | + | | Random |
|- | |- | ||
+ | | 0x4 | ||
| 0x1 | | 0x1 | ||
− | | | + | | |
− | |||
|- | |- | ||
− | | | + | | 0x5 |
| 0x1 | | 0x1 | ||
− | | | + | | |
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
+ | | 0x6 | ||
| 0x4 | | 0x4 | ||
− | | | + | | Id (ASCII string) |
− | |||
|- | |- | ||
− | | | + | | 0xA |
| 0x1 | | 0x1 | ||
− | | | + | | |
|- | |- | ||
− | | | + | | 0xB |
− | | | + | | 0x1 |
− | | | + | | |
|- | |- | ||
− | | | + | | 0xC |
− | |||
− | |||
− | |||
− | |||
| 0x1 | | 0x1 | ||
− | | | + | | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | == | + | == CardId1Mirror == |
− | + | This field mirrors bit 5 of the [[Filesystem_services#MemoryType|MemoryType]] field from the [[Filesystem_services#CardId1|CardId1]]. | |
− | |||
− | |||
+ | = CardCommand = | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
Line 914: | Line 616: | ||
| 0x0 | | 0x0 | ||
| 0x1 | | 0x1 | ||
− | | | + | | [[#CommandId|CommandId]] |
|- | |- | ||
| 0x1 | | 0x1 | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
| 0xF | | 0xF | ||
− | | | + | | CommandData |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|} | |} | ||
− | == | + | == CommandId == |
− | + | These commands are issued by the Gamecard ASIC to the actual Gamecard using the [[#AsicOperation|OperationData]] passed to [[#SendCardCommand|SendCardCommand]]. | |
− | + | Additional data buffers are then read/written as pages of 0x200 bytes each, using standard MMC read/write commands. | |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Value |
− | |||
! Description | ! Description | ||
|- | |- | ||
− | | | + | | 0x6 |
− | | | + | | |
− | | | + | |- |
+ | | 0xF | ||
+ | | T1ReadUid | ||
|- | |- | ||
− | | | + | | 0x10 |
− | | | + | | DebugReadId1 |
− | |||
|- | |- | ||
− | | | + | | 0x11 |
− | | | + | | DebugReadId2 |
− | |||
|- | |- | ||
− | | | + | | 0x12 |
− | | | + | | DebugReadId3 |
− | |||
|- | |- | ||
− | | | + | | 0x13 |
− | | | + | | DebugReadUid |
− | |||
|- | |- | ||
− | | | + | | 0x15 |
− | | | + | | DebugReadCrc |
− | |||
|- | |- | ||
− | | | + | | 0x16 |
− | | | + | | DebugWritePage |
− | |||
|- | |- | ||
− | | | + | | 0x17 |
− | | | + | | |
− | |||
|- | |- | ||
− | | | + | | 0x18 |
− | | | + | | DebugErase |
− | |||
|- | |- | ||
− | | | + | | 0x19 |
− | | | + | | DebugReadParameter |
− | |||
|- | |- | ||
| 0x20 | | 0x20 | ||
− | | | + | | DebugWriteParameter |
− | | | + | |- |
− | | | + | | 0x21 |
− | + | | T1ReadPage | |
− | + | |- | |
− | + | | 0x22 | |
− | + | | | |
− | |||
− | |||
− | |||
|- | |- | ||
− | + | | 0x28 | |
− | + | | ReadId2 | |
− | |||
|- | |- | ||
− | | | + | | 0x2E |
− | | | + | | ForceErase |
− | |||
|- | |- | ||
− | | | + | | 0x30 |
− | | | + | | T1ReadId3 |
− | |||
|- | |- | ||
− | | | + | | 0x39 |
− | | | + | | T1SetKey |
− | |||
|- | |- | ||
− | | | + | | 0x56 |
− | | | + | | ReadId1 |
− | |||
|- | |- | ||
− | | | + | | 0x59 |
− | | | + | | |
− | |||
|- | |- | ||
− | | | + | | 0x5B |
− | | | + | | ReadPage |
− | |||
|- | |- | ||
− | | | + | | 0x67 |
− | | | + | | T1ReadId1 |
− | |||
|- | |- | ||
− | | | + | | 0x83 |
− | | | + | | T1WritePage |
− | |||
|- | |- | ||
− | | | + | | 0x8A |
− | | | + | | |
− | |||
|- | |- | ||
− | | | + | | 0xA5 |
− | | | + | | ReadId3 |
− | |||
|- | |- | ||
− | | | + | | 0xB8 |
− | | | + | | T1Refresh |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
− | + | | 0xC4 | |
− | + | | T1ReadId2 | |
− | |||
|- | |- | ||
− | | | + | | 0xE0 |
− | | | + | | ReadInitialData |
− | |||
|- | |- | ||
− | | | + | | 0xE2 |
− | | | + | | ChangeInitialData |
− | |||
|- | |- | ||
− | | | + | | 0xE3 |
− | | | + | | T2ReceiveCertificate |
− | |||
|- | |- | ||
− | | | + | | 0xE4 |
− | | | + | | T2SendSocCertificate |
− | |||
|- | |- | ||
− | | | + | | 0xE5 |
− | | | + | | |
− | |||
|- | |- | ||
− | | | + | | 0xE6 |
− | | | + | | T2ReceiveRandomValue |
− | |||
|- | |- | ||
− | | | + | | 0xE7 |
− | | | + | | T2SendRandomValue |
− | |||
|- | |- | ||
− | | | + | | 0xE8 |
− | | | + | | T2ReceiveDeviceChallenge |
− | |||
|- | |- | ||
− | | | + | | 0xE9 |
− | | | + | | T2RespondDeviceChallenge |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
− | + | | 0xEA | |
− | + | | T2SendHostChallenge | |
|- | |- | ||
− | | | + | | 0xEB |
− | | | + | | T2ReceiveChallengeResponse |
|- | |- | ||
− | | | + | | 0xEC |
− | | | + | | |
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
− | + | | 0xED | |
− | + | | | |
|- | |- | ||
− | | | + | | 0xEE |
− | | | + | | |
|- | |- | ||
− | | | + | | 0xEF |
− | | | + | | |
|- | |- | ||
− | | | + | | 0xF1 |
− | | | + | | |
|- | |- | ||
− | | | + | | 0xFA |
− | | | + | | |
|} | |} | ||
− | = | + | = AsicFirmware = |
− | + | This is the Gamecard ASIC's user firmware (Lotus ASIC Firmware or LAFW) uploaded through the [[#SendFirmware|SendFirmware]] operation. | |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 1,170: | Line 784: | ||
|- | |- | ||
| 0x104 | | 0x104 | ||
− | | | + | | 0x1 |
− | | | + | | ProductionFirmwareFlag |
+ | |- | ||
+ | | 0x105 | ||
+ | | 0x1 | ||
+ | | DevelopmentFirmwareFlag | ||
|- | |- | ||
− | | | + | | 0x106 |
− | | | + | | 0x1 |
− | | | + | | WriterFirmwareFlag |
|- | |- | ||
− | | | + | | 0x107 |
− | | | + | | 0x9 |
− | | | + | | Reserved |
|- | |- | ||
| 0x110 | | 0x110 | ||
− | | | + | | 0x8 |
− | | | + | | [[#FirmwareVersion|FirmwareVersion]] |
− | |||
− | |||
− | |||
− | |||
|- | |- | ||
| 0x118 | | 0x118 | ||
| 0x4 | | 0x4 | ||
− | | | + | | FirmwareSize |
|- | |- | ||
| 0x11C | | 0x11C | ||
| 0x4 | | 0x4 | ||
− | | | + | | Reserved |
|- | |- | ||
| 0x120 | | 0x120 | ||
| 0x10 | | 0x10 | ||
− | | | + | | Iv |
|- | |- | ||
| 0x130 | | 0x130 | ||
| 0x10 | | 0x10 | ||
− | | | + | | Lotus3DeviceId |
|- | |- | ||
| 0x140 | | 0x140 | ||
| 0x40 | | 0x40 | ||
− | | | + | | Reserved |
|- | |- | ||
| 0x180 | | 0x180 | ||
| 0x7680 | | 0x7680 | ||
− | | | + | | FirmwareData |
|} | |} | ||
− | == | + | == FirmwareVersion == |
− | + | {| class="wikitable" border="1" | |
− | + | |- | |
− | + | ! Bits | |
− | + | ! Description | |
− | + | |- | |
− | + | | 0-61 | |
− | + | | Version (0, 0x1, [4.0.0+] 0x3, [9.0.0+] 0x7, [11.0.0+] 0xF, [12.0.0+] 0x1F) | |
− | [4.0.0+] | + | |- |
− | + | | 62 | |
− | [9.0.0+] | + | | IsDevelopment |
− | + | |- | |
− | [11.0.0+] | + | | 63 |
− | + | | IsProduction | |
− | [12.0.0+] | + | |} |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
== Anti-downgrade == | == Anti-downgrade == | ||
− | Loading | + | Loading a firmware blob will burn as many OTP fuses as those specified by the [[#FirmwareVersion|Version]] field. This will lock the Gamecard ASIC to only allow running firmware blobs with the same or higher version number. |
Latest revision as of 21:57, 3 December 2024
Lotus3 is the Gamecard ASIC, which is a separate chip on the motherboard responsible for communicating with the Gamecard.
It is the Tegra's SDMMC2 device on the Switch and FS communicates with it using a custom protocol based on vendor specific MMC commands.
Protocol
All communication is done using custom MMC_SEND_MANUFACTURER commands.
Value | Description |
---|---|
60 | WriteOperation |
61 | FinishOperation |
62 | Sleep |
63 | UpdateKey |
WriteOperation
Sends a Gamecard ASIC operation.
FinishOperation
Returns the status of a completed Gamecard ASIC operation.
Sleep
Puts the Gamecard ASIC in sleep mode.
UpdateKey
Tells the Gamecard ASIC to generate new random key data.
AsicOperation
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | OperationId |
0x1 | 0x1F | OperationData |
0x20 | 0x20 | CvValue (secure mode only) |
OperationId
The Gamecard ASIC supports a total of 20 operation commands. These commands are passed to the ASIC using the WriteOperation MMC command.
Additional data buffers are then read/written as pages of 0x200 bytes each, using standard MMC read/write commands.
Value | Description |
---|---|
0x01 | SendFirmware |
0x02 | ReceiveCertificate |
0x03 | SendSocCertificate |
0x04 | ReceiveRandomValue |
0x05 | SendRandomValue |
0x06 | ReceiveDeviceChallenge |
0x07 | RespondDeviceChallenge |
0x08 | SendHostChallenge |
0x09 | ReceiveChallengeResponse |
0x0A | ChangeModeToSecure |
0x0B | WriteRegister |
0x0C | ReadRegister |
0x0D | ChangeGcModeToDebug |
0x0E | GetCardHeader |
0x0F | ChangeGcModeToSecure |
0x10 | SendCardCommand |
0x11 | EnableCardBus |
0x12 | ExchangeRandomValuesInSecureMode |
0x13 | ReadRmaInformation |
0x14 | [9.0.0+] ChallengeCardExistence |
SendFirmware
Signals the Gamecard ASIC to receive the firmware.
This is the only operation handled by the Gamecard ASIC's bootrom.
ReceiveCertificate
Signals the Gamecard ASIC to send the ASIC's certificate.
SendSocCertificate
Signals the Gamecard ASIC to receive the certificate from GetGameCardCertificate.
ReceiveRandomValue
Signals the Gamecard ASIC to send a RSA-OAEP encrypted message to be decrypted by the host library.
The decrypted message will be used to generate a common AES-128 (CBC and CTR) key and IV/CTR shared between the ASIC and the host library.
SendRandomValue
Signals the Gamecard ASIC to receive a RSA-OAEP encrypted message to be decrypted by the ASIC.
The decrypted message will be used to generate a common AES-128 (CBC and CTR) key and IV/CTR shared between the ASIC and the host library.
ReceiveDeviceChallenge
Signals the Gamecard ASIC to send AES-128-CBC encrypted authentication data to be decrypted and hashed by the host library.
RespondDeviceChallenge
Signals the Gamecard ASIC to receive the AES-128-CBC encrypted hash of the ASIC authentication data.
SendHostChallenge
Signals the Gamecard ASIC to receive AES-128-CBC encrypted authentication data to be decrypted and hashed by the ASIC.
ReceiveChallengeResponse
Signals the Gamecard ASIC to send the AES-128-CBC encrypted hash of the library authentication data.
ChangeModeToSecure
Signals the Gamecard ASIC to enter secure mode.
In secure mode, all communication with the Gamecard ASIC must be AES-128-CTR encrypted.
WriteRegister
Signals the Gamecard ASIC to write an internal register.
OperationData becomes:
Offset | Size | Description |
---|---|---|
0x0 | 0x3 | Reserved |
0x3 | 0x4 | RegisterAddress |
0x7 | 0x18 | Reserved |
RegisterValue is passed in a data page.
ReadRegister
Signals the Gamecard ASIC to send the contents of its registers.
ChangeGcModeToDebug
Signals the Gamecard ASIC to change into debug mode and send information on the current Gamecard.
GetCardHeader
Signals the Gamecard ASIC to send the current Gamecard's header.
ChangeGcModeToSecure
Signals the Gamecard ASIC to enable secure communication with the Gamecard and return its key area.
SendCardCommand
Signals the Gamecard ASIC to relay commands to the Gamecard.
OperationData becomes:
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | PageSize |
0x1 | 0x1 | Direction (0 = Read, 1 = Write) |
0x2 | 0x1 | Reserved |
0x3 | 0x4 | PageNumber |
0x7 | 0x10 | CardCommand |
0x17 | 0x8 | Reserved |
EnableCardBus
Signals the Gamecard ASIC to enable the Gamecard's bus line.
ExchangeRandomValuesInSecureMode
Signals the Gamecard ASIC to exchange random authentication values with the current Gamecard.
OperationData becomes:
Offset | Size | Description |
---|---|---|
0x0 | 0x1F | RandomValues |
The Gamecard's response is returned in a data page.
ReadRmaInformation
Signals the Gamecard ASIC to send information on the Gamecard ASIC. This is called by GetGameCardAsicInfo.
ChallengeCardExistence
Signals the Gamecard ASIC to exchange random values with the current Gamecard.
OperationData becomes:
Offset | Size | Description |
---|---|---|
0x0 | 0x1F | RandomValues |
The Gamecard's response is returned in a data page.
AsicRegisters
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | Lotus3Status |
0x4 | 0x4 | AccCtrl1 |
0x8 | 0x4 | Wait1TimeRead |
0xC | 0x4 | Wait2TimeRead |
0x10 | 0x4 | Wait1TimeWrite |
0x14 | 0x4 | Wait2TimeWrite |
0x18 | 0x4 | PageRemainder |
0x1C | 0x4 | LatencyTime |
0x20 | 0x4 | LimArea |
0x24 | 0x4 | CupVersion |
0x28 | 0x4 | Lotus3Version |
0x2C | 0x4 | Standby2 |
CardHeader
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | CupVersion |
0x4 | 0x4 | CardId1 |
0x8 | 0x100 | CardHeader (without the signature) |
0x108 | 0xD8 | Reserved |
0x1E0 | 0x20 | [11.0.0+] SHA-256 hash of the data from 0 to 0x1E0 ([1.0.0-10.2.0] Reserved) |
CardKeyArea
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | SecurityLevel |
0x4 | 0x4 | Lotus3Status |
0x8 | 0x4 | CardId1 |
0xC | 0x4 | CardId2 |
0x10 | 0x40 | CardUid |
0x50 | 0x1B0 | Reserved |
0x200 | 0x200 | CertArea |
0x400 | 0x200 | Reserved |
0x600 | 0x200 | InitialData |
[11.0.0+] This is now:
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | SecurityLevel |
0x4 | 0x4 | Lotus3Status |
0x8 | 0x4 | CardId1 |
0xC | 0x4 | CardId2 |
0x10 | 0x40 | CardUid |
0x50 | 0x1B0 | Reserved |
0x200 | 0x200 | CertArea |
0x400 | 0x200 | InitialData |
CardUid
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | MakerId |
0x1 | 0x1 | |
0x2 | 0x1 | |
0x3 | 0xD | UniqueData |
0x10 | 0x1 | Reserved (always 0) |
0x11 | 0xB | Reserved (always all 0xFF) |
0x1C | 0x4 | CardId1Mirror |
0x20 | 0x20 | Hash |
MakerId
Value | Description |
---|---|
0 | MegaChips (Macronix) |
1 | Lapis |
2 |
UniqueData
While presumed to be random, this field actually has some degree of determinism depending on the MakerId.
MakerId 0:
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | Type (4 = T1RomLate, 8 = T1RomFast) |
0x1 | 0x1 | Line (0x21 for T1RomLate, incrementing value for T1RomFast) |
0x2 | 0x3 | Id |
0x5 | 0x2 | X (16-bit coordinate?) |
0x7 | 0x2 | Y (16-bit coordinate?) |
0x9 | 0x4 | Random |
MakerId 1:
Offset | Size | Description |
---|---|---|
0x0 | 0x2 | Line (incrementing value) |
0x2 | 0x3 | Id |
0x5 | 0x1 | |
0x6 | 0x1 | Version (0 or 1) |
0x7 | 0x2 | |
0x9 | 0x4 | Random |
MakerId 2:
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | Random |
0x4 | 0x1 | |
0x5 | 0x1 | |
0x6 | 0x4 | Id (ASCII string) |
0xA | 0x1 | |
0xB | 0x1 | |
0xC | 0x1 |
CardId1Mirror
This field mirrors bit 5 of the MemoryType field from the CardId1.
CardCommand
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | CommandId |
0x1 | 0xF | CommandData |
CommandId
These commands are issued by the Gamecard ASIC to the actual Gamecard using the OperationData passed to SendCardCommand.
Additional data buffers are then read/written as pages of 0x200 bytes each, using standard MMC read/write commands.
Value | Description |
---|---|
0x6 | |
0xF | T1ReadUid |
0x10 | DebugReadId1 |
0x11 | DebugReadId2 |
0x12 | DebugReadId3 |
0x13 | DebugReadUid |
0x15 | DebugReadCrc |
0x16 | DebugWritePage |
0x17 | |
0x18 | DebugErase |
0x19 | DebugReadParameter |
0x20 | DebugWriteParameter |
0x21 | T1ReadPage |
0x22 | |
0x28 | ReadId2 |
0x2E | ForceErase |
0x30 | T1ReadId3 |
0x39 | T1SetKey |
0x56 | ReadId1 |
0x59 | |
0x5B | ReadPage |
0x67 | T1ReadId1 |
0x83 | T1WritePage |
0x8A | |
0xA5 | ReadId3 |
0xB8 | T1Refresh |
0xC4 | T1ReadId2 |
0xE0 | ReadInitialData |
0xE2 | ChangeInitialData |
0xE3 | T2ReceiveCertificate |
0xE4 | T2SendSocCertificate |
0xE5 | |
0xE6 | T2ReceiveRandomValue |
0xE7 | T2SendRandomValue |
0xE8 | T2ReceiveDeviceChallenge |
0xE9 | T2RespondDeviceChallenge |
0xEA | T2SendHostChallenge |
0xEB | T2ReceiveChallengeResponse |
0xEC | |
0xED | |
0xEE | |
0xEF | |
0xF1 | |
0xFA |
AsicFirmware
This is the Gamecard ASIC's user firmware (Lotus ASIC Firmware or LAFW) uploaded through the SendFirmware operation.
Offset | Size | Description |
---|---|---|
0x0 | 0x100 | RSA-2048 PKCS #1 signature over the firmware (data from 0x100 to 0x7800) |
0x100 | 0x4 | Magic ("LAFW") |
0x104 | 0x1 | ProductionFirmwareFlag |
0x105 | 0x1 | DevelopmentFirmwareFlag |
0x106 | 0x1 | WriterFirmwareFlag |
0x107 | 0x9 | Reserved |
0x110 | 0x8 | FirmwareVersion |
0x118 | 0x4 | FirmwareSize |
0x11C | 0x4 | Reserved |
0x120 | 0x10 | Iv |
0x130 | 0x10 | Lotus3DeviceId |
0x140 | 0x40 | Reserved |
0x180 | 0x7680 | FirmwareData |
FirmwareVersion
Bits | Description |
---|---|
0-61 | Version (0, 0x1, [4.0.0+] 0x3, [9.0.0+] 0x7, [11.0.0+] 0xF, [12.0.0+] 0x1F) |
62 | IsDevelopment |
63 | IsProduction |
Anti-downgrade
Loading a firmware blob will burn as many OTP fuses as those specified by the Version field. This will lock the Gamecard ASIC to only allow running firmware blobs with the same or higher version number.