Line 1: |
Line 1: |
− | The Gamecard ASIC (known internally as the LOTUS3) is a separate chip on the motherboard responsible for communicating with the [[Gamecard]].
| + | 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 [[Filesystem_services|FS]] communicates with it using a custom protocol based on vendor specific MMC commands. | | It is the Tegra's SDMMC2 device on the Switch and [[Filesystem_services|FS]] communicates with it using a custom protocol based on vendor specific MMC commands. |
| | | |
| = Protocol = | | = Protocol = |
− | All communication is done using the following MMC_SEND_MANUFACTURER commands. | + | All communication is done using custom MMC_SEND_MANUFACTURER commands. |
| | | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
| |- | | |- |
− | ! Command | + | ! Value |
− | ! Name | + | ! Description |
| |- | | |- |
| | 60 | | | 60 |
− | | [[#WriteOperation]] | + | | [[#WriteOperation|WriteOperation]] |
| |- | | |- |
| | 61 | | | 61 |
− | | [[#GetOperationStatus]] | + | | [[#FinishOperation|FinishOperation]] |
| |- | | |- |
| | 62 | | | 62 |
− | | [[#PutToSleep]] | + | | [[#Sleep|Sleep]] |
| |- | | |- |
| | 63 | | | 63 |
− | | [[#ResetKeyData]] | + | | [[#UpdateKey|UpdateKey]] |
| |} | | |} |
| | | |
| == WriteOperation == | | == WriteOperation == |
− | Submits a Gamecard ASIC [[#ASIC commands|operation]] using a 0x40 byte sized buffer as follows.
| + | Sends a Gamecard ASIC [[#AsicOperation|operation]]. |
| + | |
| + | == FinishOperation == |
| + | Returns the status of a completed Gamecard ASIC operation. |
| + | |
| + | == Sleep == |
| + | Puts the Gamecard ASIC in sleep mode. |
| | | |
− | === OperationBuffer === | + | == 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 |
− | | Gamecard ASIC [[#ASIC commands|operation command]] | + | | [[#OperationId|OperationId]] |
| |- | | |- |
| | 0x1 | | | 0x1 |
| | 0x1F | | | 0x1F |
− | | Operation specific data | + | | OperationData |
| |- | | |- |
| | 0x20 | | | 0x20 |
| | 0x20 | | | 0x20 |
− | | Command verification value (secure mode only) | + | | CvValue (secure mode only) |
| |} | | |} |
| | | |
− | == GetOperationStatus == | + | == OperationId == |
− | Returns the status of a completed operation.
| + | The Gamecard ASIC supports a total of 20 operation commands. These commands are passed to the ASIC using the [[#WriteOperation|WriteOperation]] MMC command. |
− | | |
− | == PutToSleep ==
| |
− | Puts the Gamecard ASIC in sleep mode.
| |
− | | |
− | == ResetKeyData ==
| |
− | Tells the Gamecard ASIC to generate new random key data.
| |
− | | |
− | = ASIC commands =
| |
− | The Gamecard ASIC supports a total of 19 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" |
| |- | | |- |
− | ! Command | + | ! Value |
− | ! Name | + | ! Description |
| |- | | |- |
| | 0x01 | | | 0x01 |
− | | [[#SetUserAsicFirmware]] | + | | [[#SendFirmware|SendFirmware]] |
| |- | | |- |
| | 0x02 | | | 0x02 |
− | | [[#GetAsicCert]] | + | | [[#ReceiveCertificate|ReceiveCertificate]] |
| |- | | |- |
| | 0x03 | | | 0x03 |
− | | [[#SetEmmcEmbeddedSocCertificate]] | + | | [[#SendSocCertificate|SendSocCertificate]] |
| |- | | |- |
| | 0x04 | | | 0x04 |
− | | [[#GetAsicEncryptedMessage]] | + | | [[#ReceiveRandomValue|ReceiveRandomValue]] |
| |- | | |- |
| | 0x05 | | | 0x05 |
− | | [[#SetLibraryEncryptedMessage]] | + | | [[#SendRandomValue|SendRandomValue]] |
| |- | | |- |
| | 0x06 | | | 0x06 |
− | | [[#GetAsicAuthenticationData]] | + | | [[#ReceiveDeviceChallenge|ReceiveDeviceChallenge]] |
| |- | | |- |
| | 0x07 | | | 0x07 |
− | | [[#SetAsicAuthenticationDataHash]] | + | | [[#RespondDeviceChallenge|RespondDeviceChallenge]] |
| |- | | |- |
| | 0x08 | | | 0x08 |
− | | [[#SetLibraryAuthenticationData]] | + | | [[#SendHostChallenge|SendHostChallenge]] |
| |- | | |- |
| | 0x09 | | | 0x09 |
− | | [[#GetLibraryAuthenticationDataHash]] | + | | [[#ReceiveChallengeResponse|ReceiveChallengeResponse]] |
| |- | | |- |
| | 0x0A | | | 0x0A |
− | | [[#EnterSecureAsicMode]] | + | | [[#ChangeModeToSecure|ChangeModeToSecure]] |
| |- | | |- |
| | 0x0B | | | 0x0B |
− | | [[#WriteAsicRegister]] | + | | [[#WriteRegister|WriteRegister]] |
| |- | | |- |
| | 0x0C | | | 0x0C |
− | | [[#ReadAsicRegister]] | + | | [[#ReadRegister|ReadRegister]] |
| |- | | |- |
| | 0x0D | | | 0x0D |
− | | [[#ChangeDebugMode]] | + | | [[#ChangeGcModeToDebug|ChangeGcModeToDebug]] |
| |- | | |- |
| | 0x0E | | | 0x0E |
− | | [[#GetCardHeader]] | + | | [[#GetCardHeader|GetCardHeader]] |
| |- | | |- |
| | 0x0F | | | 0x0F |
− | | [[#GetCardKeyArea]] | + | | [[#ChangeGcModeToSecure|ChangeGcModeToSecure]] |
| |- | | |- |
| | 0x10 | | | 0x10 |
− | | [[#SendCardCommand]] | + | | [[#SendCardCommand|SendCardCommand]] |
| |- | | |- |
| | 0x11 | | | 0x11 |
− | | [[#EnableCardBus]] | + | | [[#EnableCardBus|EnableCardBus]] |
| |- | | |- |
| | 0x12 | | | 0x12 |
− | | [[#ExchangeRandomValuesInSecureMode]] | + | | [[#ExchangeRandomValuesInSecureMode|ExchangeRandomValuesInSecureMode]] |
| |- | | |- |
| | 0x13 | | | 0x13 |
− | | [[#GetRmaInformation]] | + | | [[#ReadRmaInformation|ReadRmaInformation]] |
| + | |- |
| + | | 0x14 |
| + | | [9.0.0+] [[#ChallengeCardExistence|ChallengeCardExistence]] |
| |} | | |} |
| | | |
− | == SetUserAsicFirmware == | + | === SendFirmware === |
− | Signals the Gamecard ASIC to receive a 0x7800 byte sized buffer containing the [[#User firmware|ASIC's user firmware]]. | + | 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 send the ASIC's certificate. |
| | | |
− | == GetAsicCert == | + | === SendSocCertificate === |
− | Signals the Gamecard ASIC to send a 0x400 byte sized buffer containing the ASIC's certificate. | + | Signals the Gamecard ASIC to receive the certificate from [[Settings_services#GetGameCardCertificate|GetGameCardCertificate]]. |
| | | |
− | == SetEmmcEmbeddedSocCertificate == | + | === ReceiveRandomValue === |
− | Signals the Gamecard ASIC to receive a 0x400 byte sized buffer containing the certificate from [[Settings_services#GetGameCardCertificate|GetGameCardCertificate]]. | + | Signals the Gamecard ASIC to send a RSA-OAEP encrypted message to be decrypted by the host library. |
| | | |
− | == GetAsicEncryptedMessage ==
| + | 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. |
− | Signals the Gamecard ASIC to send a 0x100 byte sized buffer containing 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.
| |
| | | |
− | == SetLibraryEncryptedMessage == | + | === SendRandomValue === |
− | Signals the Gamecard ASIC to receive a 0x100 byte sized buffer containing 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. | + | Signals the Gamecard ASIC to receive a RSA-OAEP encrypted message to be decrypted by the ASIC. |
| | | |
− | == GetAsicAuthenticationData ==
| + | 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. |
− | Signals the Gamecard ASIC to send a 0x20 byte sized buffer containing AES-128-CBC encrypted authentication data to be decrypted and hashed by the host library.
| |
| | | |
− | == SetAsicAuthenticationDataHash == | + | === ReceiveDeviceChallenge === |
− | Signals the Gamecard ASIC to receive a 0x20 byte sized buffer containing the AES-128-CBC encrypted hash of the ASIC authentication data. | + | Signals the Gamecard ASIC to send AES-128-CBC encrypted authentication data to be decrypted and hashed by the host library. |
| | | |
− | == SetLibraryAuthenticationData == | + | === RespondDeviceChallenge === |
− | Signals the Gamecard ASIC to receive a 0x20 byte sized buffer containing AES-128-CBC encrypted authentication data to be decrypted and hashed by the ASIC. | + | Signals the Gamecard ASIC to receive the AES-128-CBC encrypted hash of the ASIC authentication data. |
| | | |
− | == GetLibraryAuthenticationDataHash == | + | === SendHostChallenge === |
− | Signals the Gamecard ASIC to send a 0x20 byte sized buffer containing the AES-128-CBC encrypted hash of the library authentication data. | + | Signals the Gamecard ASIC to receive AES-128-CBC encrypted authentication data to be decrypted and hashed by the ASIC. |
| | | |
− | == EnterSecureAsicMode == | + | === ReceiveChallengeResponse === |
− | Signals the Gamecard ASIC to enter secure mode. In secure mode, all communication with the Gamecard ASIC must be AES-128-CTR encrypted. | + | Signals the Gamecard ASIC to send the AES-128-CBC encrypted hash of the library authentication data. |
| | | |
− | == WriteAsicRegister == | + | === ChangeModeToSecure === |
− | Signals the Gamecard ASIC to write an internal register. The register value is passed in the first word of a 0x200 byte sized buffer while the register index is passed in the actual [[#OperationBuffer]] as follows. | + | 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. |
| + | |
| + | [[#AsicOperation|OperationData]] becomes: |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! 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 [[#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 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 === |
| + | Signals the Gamecard ASIC to relay commands to the Gamecard. |
| + | |
| + | [[#AsicOperation|OperationData]] becomes: |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
| |- | | |- |
Line 165: |
Line 214: |
| | 0x0 | | | 0x0 |
| | 0x1 | | | 0x1 |
− | | Gamecard ASIC operation command (0x0B) | + | | PageSize |
| |- | | |- |
| | 0x1 | | | 0x1 |
| + | | 0x1 |
| + | | Direction (0 = Read, 1 = Write) |
| + | |- |
| + | | 0x2 |
| + | | 0x1 |
| + | | Reserved |
| + | |- |
| | 0x3 | | | 0x3 |
− | | Padding | + | | 0x4 |
| + | | PageNumber |
| + | |- |
| + | | 0x7 |
| + | | 0x10 |
| + | | [[#CardCommand|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. |
| + | |
| + | [[#AsicOperation|OperationData]] becomes: |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! 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 [[Filesystem_services#IDeviceOperator|GetGameCardAsicInfo]]. |
| + | |
| + | === ChallengeCardExistence === |
| + | Signals the Gamecard ASIC to exchange random values with the current Gamecard. |
| + | |
| + | [[#AsicOperation|OperationData]] becomes: |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| + | |- |
| + | | 0x0 |
| + | | 0x1F |
| + | | RandomValues |
| + | |} |
| + | |
| + | The Gamecard's response is returned in a data page. |
| + | |
| + | = AsicRegisters = |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| + | |- |
| + | | 0x0 |
| + | | 0x4 |
| + | | Lotus3Status |
| |- | | |- |
| | 0x4 | | | 0x4 |
| | 0x4 | | | 0x4 |
− | | Gamecard ASIC register index | + | | [[XCI#AccCtrl1|AccCtrl1]] |
| |- | | |- |
| | 0x8 | | | 0x8 |
| + | | 0x4 |
| + | | Wait1TimeRead |
| + | |- |
| + | | 0xC |
| + | | 0x4 |
| + | | Wait2TimeRead |
| + | |- |
| + | | 0x10 |
| + | | 0x4 |
| + | | Wait1TimeWrite |
| + | |- |
| + | | 0x14 |
| + | | 0x4 |
| + | | Wait2TimeWrite |
| + | |- |
| | 0x18 | | | 0x18 |
− | | Empty | + | | 0x4 |
| + | | PageRemainder |
| + | |- |
| + | | 0x1C |
| + | | 0x4 |
| + | | LatencyTime |
| |- | | |- |
| | 0x20 | | | 0x20 |
− | | 0x20 | + | | 0x4 |
− | | Command verification value | + | | LimArea |
| + | |- |
| + | | 0x24 |
| + | | 0x4 |
| + | | CupVersion |
| + | |- |
| + | | 0x28 |
| + | | 0x4 |
| + | | Lotus3Version |
| + | |- |
| + | | 0x2C |
| + | | 0x4 |
| + | | Standby2 |
| |} | | |} |
| | | |
− | == ReadAsicRegister == | + | = CardHeader = |
− | Signals the Gamecard ASIC to send a 0x30 byte sized buffer containing the values of all ASIC registers.
| |
− | | |
− | == ChangeDebugMode ==
| |
− | Signals the Gamecard ASIC to change into debug mode and send a 0x200 byte sized buffer containing information on the current Gamecard.
| |
− | | |
− | == GetCardHeader ==
| |
− | Signals the Gamecard ASIC to send a 0x108 byte sized buffer containing the current Gamecard's header data as follows.
| |
− | | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
| |- | | |- |
Line 200: |
Line 341: |
| |- | | |- |
| | 0x0 | | | 0x0 |
− | | 0x8 | + | | 0x4 |
− | | Unknown | + | | CupVersion |
| + | |- |
| + | | 0x4 |
| + | | 0x4 |
| + | | [[Filesystem_services#CardId1|CardId1]] |
| |- | | |- |
| | 0x8 | | | 0x8 |
| | 0x100 | | | 0x100 |
− | | [[Gamecard_Format#Gamecard_Header|Gamecard header]] (without the signature) | + | | [[XCI#CardHeader|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) |
| |} | | |} |
| | | |
− | == GetCardKeyArea == | + | = CardKeyArea = |
− | Signals the Gamecard ASIC to send a 0x800 byte sized buffer containing the current Gamecard's key area sectors.
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| + | |- |
| + | | 0x0 |
| + | | 0x4 |
| + | | SecurityLevel |
| + | |- |
| + | | 0x4 |
| + | | 0x4 |
| + | | Lotus3Status |
| + | |- |
| + | | 0x8 |
| + | | 0x4 |
| + | | [[Filesystem_services#CardId1|CardId1]] |
| + | |- |
| + | | 0xC |
| + | | 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]] |
| + | |} |
| | | |
− | == SendCardCommand == | + | [11.0.0+] This is now: |
− | Signals the Gamecard ASIC to relay a specific [[#Gamecard commands|command]] to the Gamecard. The command is sent to the Gamecard using the [[#OperationBuffer]] as follows.
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| + | |- |
| + | | 0x0 |
| + | | 0x4 |
| + | | SecurityLevel |
| + | |- |
| + | | 0x4 |
| + | | 0x4 |
| + | | Lotus3Status |
| + | |- |
| + | | 0x8 |
| + | | 0x4 |
| + | | [[Filesystem_services#CardId1|CardId1]] |
| + | |- |
| + | | 0xC |
| + | | 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 222: |
Line 454: |
| | 0x0 | | | 0x0 |
| | 0x1 | | | 0x1 |
− | | Gamecard ASIC operation command (0x10) | + | | [[#MakerId|MakerId]] |
| + | |- |
| + | | 0x1 |
| + | | 0x1 |
| + | | |
| |- | | |- |
| + | | 0x2 |
| | 0x1 | | | 0x1 |
− | | 0x7 | + | | |
− | | Unknown | + | |- |
| + | | 0x3 |
| + | | 0xD |
| + | | [[#UniqueData|UniqueData]] |
| |- | | |- |
− | | 0x8 | + | | 0x10 |
| | 0x1 | | | 0x1 |
− | | Gamecard command | + | | Reserved (always 0) |
| |- | | |- |
− | | 0x9 | + | | 0x11 |
− | | 0x17 | + | | 0xB |
− | | Command specific data | + | | Reserved (always all 0xFF) |
| + | |- |
| + | | 0x1C |
| + | | 0x4 |
| + | | [[#CardId1Mirror|CardId1Mirror]] |
| |- | | |- |
| | 0x20 | | | 0x20 |
| | 0x20 | | | 0x20 |
− | | Command verification value | + | | Hash |
| |} | | |} |
| | | |
− | == EnableCardBus == | + | == MakerId == |
− | Signals the Gamecard ASIC to enable the current Gamecard's bus line.
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Value |
| + | ! Description |
| + | |- |
| + | | 0 |
| + | | MegaChips (Macronix) |
| + | |- |
| + | | 1 |
| + | | Lapis |
| + | |- |
| + | | 2 |
| + | | |
| + | |} |
| | | |
− | == ExchangeRandomValuesInSecureMode == | + | == UniqueData == |
− | Signals the Gamecard ASIC to exchange random authentication values with the current Gamecard. The Gamecard response values are returned in a 0x20 sized buffer while the host values are passed in the actual [[#OperationBuffer]] as follows.
| + | 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 255: |
Line 513: |
| | 0x0 | | | 0x0 |
| | 0x1 | | | 0x1 |
− | | Gamecard ASIC operation command (0x12) | + | | Type (4 = [[Filesystem_services#MemoryType|T1RomLate]], 8 = [[Filesystem_services#MemoryType|T1RomFast]]) |
| + | |- |
| + | | 0x1 |
| + | | 0x1 |
| + | | Line (0x21 for [[Filesystem_services#MemoryType|T1RomLate]], incrementing value for [[Filesystem_services#MemoryType|T1RomFast]]) |
| + | |- |
| + | | 0x2 |
| + | | 0x3 |
| + | | Id |
| + | |- |
| + | | 0x5 |
| + | | 0x2 |
| + | | X (16-bit coordinate?) |
| + | |- |
| + | | 0x7 |
| + | | 0x2 |
| + | | Y (16-bit coordinate?) |
| + | |- |
| + | | 0x9 |
| + | | 0x4 |
| + | | Random |
| + | |} |
| + | |
| + | MakerId 1: |
| + | {| class="wikitable" border="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: |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! 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 [[Filesystem_services#MemoryType|MemoryType]] field from the [[Filesystem_services#CardId1|CardId1]]. |
| + | |
| + | = CardCommand = |
| + | {| class="wikitable" border="1" |
| + | |- |
| + | ! Offset |
| + | ! Size |
| + | ! Description |
| |- | | |- |
| + | | 0x0 |
| | 0x1 | | | 0x1 |
− | | 0x1F | + | | [[#CommandId|CommandId]] |
− | | Random value from host | |
| |- | | |- |
− | | 0x20 | + | | 0x1 |
− | | 0x20 | + | | 0xF |
− | | Command verification value | + | | CommandData |
| |} | | |} |
| | | |
− | == GetRmaInformation == | + | == CommandId == |
− | Signals the Gamecard ASIC to send a 0x200 byte sized buffer containing information on the Gamecard ASIC. This is called by [[Filesystem_services#IDeviceOperator|GetGameCardAsicInfo]].
| + | These commands are issued by the Gamecard ASIC to the actual Gamecard using the [[#AsicOperation|OperationData]] passed to [[#SendCardCommand|SendCardCommand]]. |
| | | |
− | = Gamecard commands =
| + | Additional data buffers are then read/written as pages of 0x200 bytes each, using standard MMC read/write commands. |
− | These commands are issued by the Gamecard ASIC to the actual Gamecard using the [[#OperationBuffer]] passed to [[#SendCardCommand]].
| |
| | | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
| |- | | |- |
− | ! Command | + | ! Value |
− | ! Name | + | ! Description |
| + | |- |
| + | | 0x6 |
| + | | SelfRefresh |
| + | |- |
| + | | 0xF |
| + | | T1ReadUid |
| |- | | |- |
| | 0x10 | | | 0x10 |
− | | ReadId1Writer | + | | DebugReadId1 |
| |- | | |- |
| | 0x11 | | | 0x11 |
− | | ReadId2Writer | + | | DebugReadId2 |
| |- | | |- |
| | 0x12 | | | 0x12 |
− | | ReadId3Writer | + | | DebugReadId3 |
| + | |- |
| + | | 0x13 |
| + | | DebugReadUid |
| |- | | |- |
| | 0x15 | | | 0x15 |
− | | ReadCrc | + | | DebugReadCrc |
| |- | | |- |
| | 0x16 | | | 0x16 |
− | | WritePage | + | | DebugWritePage |
| + | |- |
| + | | 0x17 |
| + | | |
| |- | | |- |
| | 0x18 | | | 0x18 |
− | | Erase | + | | DebugErase |
| |- | | |- |
| | 0x19 | | | 0x19 |
− | | ReadDevParam | + | | DebugReadParameter |
| |- | | |- |
| | 0x20 | | | 0x20 |
− | | WriteDevParam | + | | DebugWriteParameter |
| |- | | |- |
| | 0x21 | | | 0x21 |
− | | ReadPageSecure | + | | T1ReadPage |
| + | |- |
| + | | 0x22 |
| + | | |
| |- | | |- |
| | 0x28 | | | 0x28 |
− | | ReadId2Normal | + | | ReadId2 |
| |- | | |- |
| | 0x2E | | | 0x2E |
− | | | + | | ForceErase |
| |- | | |- |
| | 0x30 | | | 0x30 |
− | | ReadId3Secure | + | | T1ReadId3 |
| |- | | |- |
| | 0x39 | | | 0x39 |
− | | | + | | T1SetKey |
| |- | | |- |
| | 0x56 | | | 0x56 |
− | | ReadId1Normal | + | | ReadId1 |
| |- | | |- |
− | | 0x83 | + | | 0x59 |
− | | WritePageSecure | + | | |
| |- | | |- |
| | 0x5B | | | 0x5B |
Line 326: |
Line 697: |
| |- | | |- |
| | 0x67 | | | 0x67 |
− | | ReadId1Secure | + | | T1ReadId1 |
| + | |- |
| + | | 0x83 |
| + | | T1WritePage |
| + | |- |
| + | | 0x8A |
| + | | |
| |- | | |- |
| | 0xA5 | | | 0xA5 |
− | | ReadId3Normal | + | | ReadId3 |
| |- | | |- |
| | 0xB8 | | | 0xB8 |
− | | | + | | T1Refresh |
| |- | | |- |
| | 0xC4 | | | 0xC4 |
− | | ReadId2Secure | + | | T1ReadId2 |
| |- | | |- |
| | 0xE0 | | | 0xE0 |
− | | | + | | ReadInitialData |
| |- | | |- |
| | 0xE2 | | | 0xE2 |
| + | | ChangeInitialData |
| + | |- |
| + | | 0xE3 |
| + | | T2ReceiveCertificate |
| + | |- |
| + | | 0xE4 |
| + | | T2SendSocCertificate |
| + | |- |
| + | | 0xE5 |
| | | | | |
− | |}
| |
− |
| |
− | = Modes =
| |
− | Both the Gamecard ASIC and the actual Gamecard can operate in different modes.
| |
− |
| |
− | == ASIC modes ==
| |
− | {| class="wikitable" border="1"
| |
| |- | | |- |
− | ! Mode
| + | | 0xE6 |
− | ! Name
| + | | T2ReceiveRandomValue |
| + | |- |
| + | | 0xE7 |
| + | | T2SendRandomValue |
| + | |- |
| + | | 0xE8 |
| + | | T2ReceiveDeviceChallenge |
| + | |- |
| + | | 0xE9 |
| + | | T2RespondDeviceChallenge |
| + | |- |
| + | | 0xEA |
| + | | T2SendHostChallenge |
| |- | | |- |
− | | 0x00 | + | | 0xEB |
− | | Initial | + | | T2ReceiveChallengeResponse |
| |- | | |- |
− | | 0x01 | + | | 0xEC |
− | | Secure | + | | |
− | |}
| |
− | | |
− | == Gamecard modes ==
| |
− | {| class="wikitable" border="1"
| |
| |- | | |- |
− | ! Mode
| + | | 0xED |
− | ! Name
| + | | |
| |- | | |- |
− | | 0x00 | + | | 0xEE |
− | | Initial | + | | |
| |- | | |- |
− | | 0x01 | + | | 0xEF |
− | | Normal | + | | |
| |- | | |- |
− | | 0x02 | + | | 0xF1 |
− | | Secure | + | | |
| |- | | |- |
− | | 0x03 | + | | 0xFA |
− | | Write | + | | ReadRefreshStatus |
| |} | | |} |
| | | |
− | = User firmware = | + | = AsicFirmware = |
− | [[Filesystem_services|FS]] provides the appropriate Gamecard ASIC's user firmware (Lotus ASIC Firmware or LAFW) which is encrypted, signed and follows the format below.
| + | 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 390: |
Line 777: |
| | 0x0 | | | 0x0 |
| | 0x100 | | | 0x100 |
− | | RSA-PKCS#1 signature | + | | RSA-2048 PKCS #1 signature over the firmware (data from 0x100 to 0x7800) |
| |- | | |- |
| | 0x100 | | | 0x100 |
Line 397: |
Line 784: |
| |- | | |- |
| | 0x104 | | | 0x104 |
− | | 0x4 | + | | 0x1 |
− | | Unknown (0xFF000000, 0xFFFF0000 or 0xFFFFFF00) | + | | ProductionFirmwareFlag |
| + | |- |
| + | | 0x105 |
| + | | 0x1 |
| + | | DevelopmentFirmwareFlag |
| |- | | |- |
− | | 0x108 | + | | 0x106 |
− | | 0x4 | + | | 0x1 |
− | | | + | | WriterFirmwareFlag |
| |- | | |- |
− | | 0x10C | + | | 0x107 |
− | | 0x4 | + | | 0x9 |
− | | | + | | Reserved |
| |- | | |- |
| | 0x110 | | | 0x110 |
− | | 0x4 | + | | 0x8 |
− | | Version (0, 1 or 3) | + | | [[#FirmwareVersion|FirmwareVersion]] |
− | |-
| |
− | | 0x114
| |
− | | 0x4
| |
− | | Unknown (0x80000000) | |
| |- | | |- |
| | 0x118 | | | 0x118 |
| | 0x4 | | | 0x4 |
− | | Data size | + | | FirmwareSize |
| |- | | |- |
| | 0x11C | | | 0x11C |
| | 0x4 | | | 0x4 |
− | | | + | | Reserved |
| |- | | |- |
| | 0x120 | | | 0x120 |
| | 0x10 | | | 0x10 |
− | | Data hash | + | | Iv |
| |- | | |- |
| | 0x130 | | | 0x130 |
| | 0x10 | | | 0x10 |
− | | Placeholder string ("IDIDIDIDIDIDIDID") | + | | Lotus3DeviceId |
| |- | | |- |
| | 0x140 | | | 0x140 |
| | 0x40 | | | 0x40 |
− | | Empty | + | | Reserved |
| |- | | |- |
| | 0x180 | | | 0x180 |
| | 0x7680 | | | 0x7680 |
− | | Encrypted data | + | | FirmwareData |
| |} | | |} |
| | | |
− | == Types == | + | == FirmwareVersion == |
− | Depending on it's purpose, multiple user firmware blobs exist.
| + | {| class="wikitable" border="1" |
− | | + | |- |
− | === FwRead ===
| + | ! Bits |
− | Code for reading retail Gamecards. Only the normal and secure [[#Gamecard modes|Gamecard modes]] are supported.
| + | ! Description |
− | | + | |- |
− | Found inside [[Filesystem_services|FS]].
| + | | 0-61 |
− | | + | | Version (0, 0x1, [4.0.0+] 0x3, [9.0.0+] 0x7, [11.0.0+] 0xF, [12.0.0+] 0x1F) |
− | [4.0.0+] This firmware blob was updated to provide support for new Gamecards. | + | |- |
− | | + | | 62 |
− | === FwWriter ===
| + | | IsDevelopment |
− | Code for writing development Gamecards. Only the normal and write [[#Gamecard modes|Gamecard modes]] are supported.
| + | |- |
− | | + | | 63 |
− | Found inside [[Filesystem_services|FS]].
| + | | IsProduction |
− | | + | |} |
− | === FwReadDev ===
| |
− | Code for reading development Gamecards. Development Gamecards use common [[Gamecard_Format#Initial_Data|initial data]] which justifies the need for a specialized read firmware.
| |
− | | |
− | Found inside [[Filesystem_services|FS]].
| |
− | | |
− | === FwDebug ===
| |
− | Code for calling [[#GetRmaInformation]]. Must be passed as an argument for [[Filesystem_services#IDeviceOperator|GetGameCardAsicInfo]].
| |
− | | |
− | Never observed (possibly factory only).
| |
| | | |
| == Anti-downgrade == | | == Anti-downgrade == |
− | Loading an user firmware blob with a certain version field will lock the Gamecard ASIC to only allow running firmware blobs with the same or higher version number. Therefore, it is speculated that the Gamecard ASIC contains some sort of non-volatile memory bank which could be used for this purpose (among others). | + | 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. |
− | | |
− | The [[#FwWriter|FwWriter]] and [[#FwReadDev|FwReadDev]] blobs' version is always 0, but [[#FwRead|FwRead]] blob's version is either 1 or 3 ([4.0.0+]). This effectively locks retail consoles from using the development firmware blobs.
| |