Difference between revisions of "Lotus3"

From Nintendo Switch Brew
Jump to navigation Jump to search
 
(10 intermediate revisions by the same user not shown)
Line 4: Line 4:
  
 
= 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
| [[#FinishOperation]]
+
| [[#FinishOperation|FinishOperation]]
 
|-
 
|-
 
| 62
 
| 62
| [[#Sleep]]
+
| [[#Sleep|Sleep]]
 
|-
 
|-
 
| 63
 
| 63
| [[#UpdateKey]]
+
| [[#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)
 
|}
 
|}
  
== FinishOperation ==
+
== 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.
 
 
== Sleep ==
 
Puts the Gamecard ASIC in sleep mode.
 
 
 
== UpdateKey ==
 
Tells the Gamecard ASIC to generate new random key data.
 
 
 
= ASIC commands =
 
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"
 
|-
 
|-
! Command
+
! Value
! Name
+
! 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 a 0x7800 byte sized buffer containing the [[#User firmware|ASIC's user firmware]].
+
Signals the Gamecard ASIC to receive the [[#AsicFirmware|firmware]].  
  
== ReceiveCertificate ==
+
This is the only operation handled by the Gamecard ASIC's bootrom.
Signals the Gamecard ASIC to send a 0x400 byte sized buffer containing the ASIC's certificate.
 
  
== SendSocCertificate ==
+
=== ReceiveCertificate ===
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 the ASIC's certificate.
  
== ReceiveRandomValue ==
+
=== SendSocCertificate ===
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.
+
Signals the Gamecard ASIC to receive the certificate from [[Settings_services#GetGameCardCertificate|GetGameCardCertificate]].
  
== SendRandomValue ==
+
=== ReceiveRandomValue ===
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 send a RSA-OAEP encrypted message to be decrypted by the host library.
  
== ReceiveDeviceChallenge ==
+
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.
 
  
== RespondDeviceChallenge ==
+
=== SendRandomValue ===
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 receive a RSA-OAEP encrypted message to be decrypted by the ASIC.
  
== SendHostChallenge ==
+
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 0x20 byte sized buffer containing AES-128-CBC encrypted authentication data to be decrypted and hashed by the ASIC.
 
  
== ReceiveChallengeResponse ==
+
=== ReceiveDeviceChallenge ===
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 send AES-128-CBC encrypted authentication data to be decrypted and hashed by the host library.
  
== ChangeModeToSecure ==
+
=== RespondDeviceChallenge ===
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 receive the AES-128-CBC encrypted hash of the ASIC authentication data.
  
== WriteRegister ==
+
=== SendHostChallenge ===
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 receive AES-128-CBC encrypted authentication data to be decrypted and hashed by the ASIC.
  
{| class="wikitable" border="1"
+
=== ReceiveChallengeResponse ===
|-
+
Signals the Gamecard ASIC to send the AES-128-CBC encrypted hash of the library authentication data.
! Offset
+
 
! Size
+
=== ChangeModeToSecure ===
! Description
+
Signals the Gamecard ASIC to enter secure mode.
|-
+
 
| 0x0
+
In secure mode, all communication with the Gamecard ASIC must be AES-128-CTR encrypted.
| 0x1
 
| Gamecard ASIC operation command (0x0B)
 
|-
 
| 0x1
 
| 0x3
 
| Padding
 
|-
 
| 0x4
 
| 0x4
 
| Gamecard ASIC register index
 
|-
 
| 0x8
 
| 0x18
 
| Empty
 
|-
 
| 0x20
 
| 0x20
 
| Command verification value
 
|}
 
  
== ReadRegister ==
+
=== WriteRegister ===
Signals the Gamecard ASIC to send a 0x30 byte sized buffer containing the values of all ASIC registers as follows.
+
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
| 0x4
+
| 0x3
| Status
+
| Reserved
 
|-
 
|-
 +
| 0x3
 
| 0x4
 
| 0x4
| 0x4
+
| RegisterAddress
| Access Control
 
|-
 
| 0x8
 
| 0x4
 
|
 
|-
 
| 0xC
 
| 0x4
 
|
 
|-
 
| 0x10
 
| 0x4
 
|
 
|-
 
| 0x14
 
| 0x4
 
|
 
 
|-
 
|-
 +
| 0x7
 
| 0x18
 
| 0x18
| 0x4
+
| Reserved
|
 
|-
 
| 0x1C
 
| 0x4
 
|
 
|-
 
| 0x20
 
| 0x4
 
|
 
|-
 
| 0x24
 
| 0x4
 
|
 
|-
 
| 0x28
 
| 0x4
 
|
 
|-
 
| 0x2C
 
| 0x4
 
|
 
 
|}
 
|}
  
== ChangeGcModeToDebug ==
+
RegisterValue is passed in a data page.
Signals the Gamecard ASIC to change into debug mode and send a 0x200 byte sized buffer containing information on the current Gamecard.
 
  
== GetCardHeader ==
+
=== ReadRegister ===
Signals the Gamecard ASIC to send a 0x108 byte sized buffer containing the current Gamecard's header data as follows.
+
Signals the Gamecard ASIC to send the contents of its [[#AsicRegisters|registers]].
  
{| class="wikitable" border="1"
+
=== ChangeGcModeToDebug ===
|-
+
Signals the Gamecard ASIC to change into debug mode and send information on the current Gamecard.
! Offset
 
! Size
 
! Description
 
|-
 
| 0x0
 
| 0x4
 
| [[Gamecard_Format#Gamecard_Info|CUP Version]]
 
|-
 
| 0x4
 
| 0x4
 
| [[#ReadId1Normal.2C_ReadId1Secure.2C_ReadId1Writer|Gamecard ID1]]
 
|-
 
| 0x8
 
| 0x100
 
| [[Gamecard_Format#Gamecard_Header|Gamecard Header]] (without the signature)
 
|}
 
  
== ChangeGcModeToSecure ==
+
=== GetCardHeader ===
Signals the Gamecard ASIC to send a 0x800 byte sized buffer containing the current Gamecard's key area sectors as follows.
+
Signals the Gamecard ASIC to send the current Gamecard's [[#CardHeader|header]].
  
{| class="wikitable" border="1"
+
=== ChangeGcModeToSecure ===
|-
+
Signals the Gamecard ASIC to enable secure communication with the Gamecard and return its [[#CardKeyArea|key area]].
! Sector
 
! Size
 
! Description
 
|-
 
| 0
 
| 0x200
 
| Gamecard specific data
 
|-
 
| 1
 
| 0x200
 
| [[Gamecard_Format#Gamecard_Certificate|Gamecard Certificate]]
 
|-
 
| 2
 
| 0x200
 
| Empty sector (all 0xFF)
 
|-
 
| 3
 
| 0x200
 
| [[Gamecard_Format#Initial_Data|Gamecard Initial Data]]
 
|}
 
  
== SendCardCommand ==
+
=== SendCardCommand ===
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.
+
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
| Gamecard ASIC operation command (0x10)
+
| PageSize
 
|-
 
|-
 
| 0x1
 
| 0x1
 
| 0x1
 
| 0x1
| Page size
+
| Direction (0 = Read, 1 = Write)
 
|-
 
|-
 
| 0x2
 
| 0x2
 
| 0x1
 
| 0x1
| Direction (0 = read, 1 = write)
+
| Reserved
 
|-
 
|-
 
| 0x3
 
| 0x3
| 0x1
 
| Padding
 
|-
 
 
| 0x4
 
| 0x4
| 0x4
+
| PageNumber
| Page count
 
 
|-
 
|-
| 0x8
+
| 0x7
| 0x1
+
| 0x10
| Gamecard command
+
| [[#CardCommand|CardCommand]]
 
|-
 
|-
| 0x9
 
 
| 0x17
 
| 0x17
| Command specific data
+
| 0x8
|-
+
| Reserved
| 0x20
 
| 0x20
 
| Command verification value
 
 
|}
 
|}
  
== EnableCardBus ==
+
=== EnableCardBus ===
Signals the Gamecard ASIC to enable the current Gamecard's bus line.
+
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. The Gamecard response values are returned in a 0x20 sized buffer while the host values are passed in the actual [[#OperationBuffer]] as follows.
+
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
| 0x1
 
| Gamecard ASIC operation command (0x12)
 
|-
 
| 0x1
 
 
| 0x1F
 
| 0x1F
| Random value from host
+
| RandomValues
|-
 
| 0x20
 
| 0x20
 
| Command verification value
 
 
|}
 
|}
  
== ReadRmaInformation ==
+
The Gamecard's response is returned in a data page.
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]].
 
  
== ChallengeCardExistence ==
+
=== ReadRmaInformation ===
Signals the Gamecard ASIC to exchange random values with the current Gamecard. The Gamecard response values are returned in a 0x58 sized buffer while the host values are passed in the actual [[#OperationBuffer]] as follows.
+
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
| 0x1
 
| Gamecard ASIC operation command (0x14)
 
|-
 
| 0x1
 
 
| 0x1F
 
| 0x1F
| Random value from host
+
| RandomValues
|-
 
| 0x20
 
| 0x20
 
| Command verification value
 
 
|}
 
|}
  
= Gamecard commands =
+
The Gamecard's response is returned in a data page.
These commands are issued by the Gamecard ASIC to the actual Gamecard using the [[#OperationBuffer]] passed to [[#SendCardCommand]].
 
 
 
Additional data buffers are then read/written using standard MMC read/write commands.  
 
  
 +
= AsicRegisters =
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Command
+
! Offset
! Name
+
! Size
 +
! Description
 +
|-
 +
| 0x0
 +
| 0x4
 +
| Lotus3Status
 
|-
 
|-
| 0x10
+
| 0x4
| [[#ReadId1|ReadId1Write]]
+
| 0x4
 +
| [[XCI#AccCtrl1|AccCtrl1]]
 
|-
 
|-
| 0x11
+
| 0x8
| [[#ReadId2|ReadId2Write]]
+
| 0x4
 +
| Wait1TimeRead
 
|-
 
|-
| 0x12
+
| 0xC
| [[#ReadId3|ReadId3Write]]
+
| 0x4
 +
| Wait2TimeRead
 
|-
 
|-
| 0x15
+
| 0x10
| [[#ReadCrc|ReadCrc]]
+
| 0x4
 +
| Wait1TimeWrite
 
|-
 
|-
| 0x16
+
| 0x14
| [[#WritePage|WritePage]]
+
| 0x4
 +
| Wait2TimeWrite
 
|-
 
|-
 
| 0x18
 
| 0x18
| [[#Erase|Erase]]
+
| 0x4
 +
| PageRemainder
 
|-
 
|-
| 0x19
+
| 0x1C
| [[#ReadParameter|ReadParameter]]
+
| 0x4
 +
| LatencyTime
 
|-
 
|-
 
| 0x20
 
| 0x20
| [[#WriteParameter|WriteParameter]]
+
| 0x4
 +
| LimArea
 
|-
 
|-
| 0x21
+
| 0x24
| [[#ReadPage|ReadPageSecure]]
+
| 0x4
 +
| CupVersion
 
|-
 
|-
 
| 0x28
 
| 0x28
| [[#ReadId2|ReadId2]]
+
| 0x4
 +
| Lotus3Version
 
|-
 
|-
| 0x2E
+
| 0x2C
| [2.0.0+] [[#ChangeDebugDirect|ChangeDebugDirect]]
+
| 0x4
|-
+
| Standby2
| 0x30
 
| [[#ReadId3|ReadId3Secure]]
 
|-
 
| 0x39
 
| [[#SetKey|SetKey]]
 
|-
 
| 0x56
 
| [[#ReadId1|ReadId1]]
 
|-
 
| 0x83
 
| [[#WritePage|WritePageSecure]]
 
|-
 
| 0x5B
 
| [[#ReadPage|ReadPage]]
 
|-
 
| 0x67
 
| [[#ReadId1|ReadId1Secure]]
 
|-
 
| 0xA5
 
| [[#ReadId3|ReadId3]]
 
|-
 
| 0xB8
 
| [[#Refresh|Refresh]]
 
|-
 
| 0xC4
 
| [[#ReadId2|ReadId2Secure]]
 
|-
 
| 0xE0
 
| ReadInitialData
 
|-
 
| 0xE2
 
| ChangeInitialData
 
 
|}
 
|}
  
== ReadId1 ==
+
= CardHeader =
Returns the Gamecard ID1 under one of the valid [[#Gamecard modes|Gamecard modes]].
 
 
 
The [[#OperationBuffer]] is as follows.
 
 
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 477: Line 341:
 
|-
 
|-
 
| 0x0
 
| 0x0
| 0x1
+
| 0x4
| Gamecard ASIC operation command (0x10)
+
| CupVersion
|-
 
| 0x1
 
| 0x1
 
| Set to 1
 
|-
 
| 0x2
 
| 0x1
 
| Set to 0
 
|-
 
| 0x3
 
| 0x1
 
| Padding
 
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Set to 0
+
| [[Filesystem_services#CardId1|CardId1]]
 
|-
 
|-
 
| 0x8
 
| 0x8
| 0x1
+
| 0x100
| Gamecard command (0x10, 0x56 or 0x67)
+
| [[XCI#CardHeader|CardHeader]] (without the signature)
 
|-
 
|-
| 0x9
+
| 0x108
| 0x4
+
| 0xD8
| Set to 0
+
| Reserved
|-
 
| 0xD
 
| 0x2
 
| Set to 0
 
|-
 
| 0xF
 
| 0x1
 
| Set to 0
 
|-
 
| 0x10
 
| 0x10
 
| Empty
 
 
|-
 
|-
 +
| 0x1E0
 
| 0x20
 
| 0x20
| 0x20
+
| [11.0.0+] SHA-256 hash of the data from 0 to 0x1E0 ([1.0.0-10.2.0] Reserved)
| Command verification value
 
 
|}
 
|}
  
== ReadId2 ==
+
= CardKeyArea =
Returns the Gamecard ID2 under one of the valid [[#Gamecard modes|Gamecard modes]].
 
 
 
The [[#OperationBuffer]] is as follows.
 
 
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 533: Line 369:
 
|-
 
|-
 
| 0x0
 
| 0x0
| 0x1
+
| 0x4
| Gamecard ASIC operation command (0x10)
+
| SecurityLevel
|-
 
| 0x1
 
| 0x1
 
| Set to 1
 
|-
 
| 0x2
 
| 0x1
 
| Set to 0
 
|-
 
| 0x3
 
| 0x1
 
| Padding
 
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Set to 0
+
| Lotus3Status
 
|-
 
|-
 
| 0x8
 
| 0x8
| 0x1
+
| 0x4
| Gamecard command (0x11, 0x28 or 0xC4)
+
| [[Filesystem_services#CardId1|CardId1]]
 
|-
 
|-
| 0x9
+
| 0xC
 
| 0x4
 
| 0x4
| Set to 0
+
| [[Filesystem_services#CardId2|CardId2]]
 
|-
 
|-
| 0xD
+
| 0x10
| 0x2
+
| 0x40
| Set to 0
+
| [[#CardUid|CardUid]]
 +
|-
 +
| 0x50
 +
| 0x1B0
 +
| Reserved
 
|-
 
|-
| 0xF
+
| 0x200
| 0x1
+
| 0x200
| Set to 0
+
| [[XCI#CertArea|CertArea]]
 
|-
 
|-
| 0x10
+
| 0x400
| 0x10
+
| 0x200
| Empty
+
| Reserved
 
|-
 
|-
| 0x20
+
| 0x600
| 0x20
+
| 0x200
| Command verification value
+
| [[XCI#InitialData|InitialData]]
 
|}
 
|}
  
== ReadId3 ==
+
[11.0.0+] This is now:
Returns the Gamecard ID3 under one of the valid [[#Gamecard modes|Gamecard modes]].
 
 
 
The [[#OperationBuffer]] is as follows.
 
 
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 589: Line 413:
 
|-
 
|-
 
| 0x0
 
| 0x0
| 0x1
+
| 0x4
| Gamecard ASIC operation command (0x10)
+
| SecurityLevel
|-
 
| 0x1
 
| 0x1
 
| Set to 1
 
|-
 
| 0x2
 
| 0x1
 
| Set to 0
 
|-
 
| 0x3
 
| 0x1
 
| Padding
 
 
|-
 
|-
 
| 0x4
 
| 0x4
 
| 0x4
 
| 0x4
| Set to 0
+
| Lotus3Status
 
|-
 
|-
 
| 0x8
 
| 0x8
| 0x1
+
| 0x4
| Gamecard command (0x12, 0x30 or 0xA5)
+
| [[Filesystem_services#CardId1|CardId1]]
 
|-
 
|-
| 0x9
+
| 0xC
 
| 0x4
 
| 0x4
| Set to 0
+
| [[Filesystem_services#CardId2|CardId2]]
 
|-
 
|-
| 0xD
+
| 0x10
| 0x2
+
| 0x40
| Set to 0
+
| [[#CardUid|CardUid]]
 
|-
 
|-
| 0xF
+
| 0x50
| 0x1
+
| 0x1B0
| Set to 0
+
| Reserved
 
|-
 
|-
| 0x10
+
| 0x200
| 0x10
+
| 0x200
| Empty
+
| [[XCI#CertArea|CertArea]]
 
|-
 
|-
| 0x20
+
| 0x400
| 0x20
+
| 0x200
| Command verification value
+
| [[XCI#InitialData|InitialData]]
 
|}
 
|}
  
== ReadCrc ==
+
= CardUid =
Reads pages from the Gamecard, calculates their CRC and returns it. This command is only available in [[#Gamecard modes|Write]] mode.
 
 
 
The [[#OperationBuffer]] is as follows.
 
 
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 646: Line 454:
 
| 0x0
 
| 0x0
 
| 0x1
 
| 0x1
| Gamecard ASIC operation command (0x10)
+
| [[#MakerId|MakerId]]
 
|-
 
|-
 
| 0x1
 
| 0x1
 
| 0x1
 
| 0x1
| Set to 1
+
|  
 
|-
 
|-
 
| 0x2
 
| 0x2
 
| 0x1
 
| 0x1
| Set to 0
+
|  
 
|-
 
|-
 
| 0x3
 
| 0x3
 +
| 0xD
 +
| [[#UniqueData|UniqueData]]
 +
|-
 +
| 0x10
 
| 0x1
 
| 0x1
| Padding
+
| Reserved (always 0)
 
|-
 
|-
| 0x4
+
| 0x11
| 0x4
+
| 0xB
| Set to 0
+
| Reserved (always all 0xFF)
 
|-
 
|-
| 0x8
+
| 0x1C
| 0x1
 
| Gamecard command (0x15)
 
|-
 
| 0x9
 
 
| 0x4
 
| 0x4
| Gamecard page offset
+
| [[#CardId1Mirror|CardId1Mirror]]
|-
 
| 0xD
 
| 0x3
 
| Gamecard page count
 
|-
 
| 0x10
 
| 0x10
 
| Empty
 
 
|-
 
|-
 
| 0x20
 
| 0x20
 
| 0x20
 
| 0x20
| Command verification value
+
| Hash
 
|}
 
|}
  
== WritePage ==
+
== MakerId ==
Writes Gamecard pages. This command is only available in [[#Gamecard modes|Write]] and [[#Gamecard modes|Secure]] modes.
 
 
 
The [[#OperationBuffer]] is as follows.
 
 
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Offset
+
! Value
! Size
 
 
! Description
 
! Description
 
|-
 
|-
| 0x0
+
| 0
| 0x1
+
| MegaChips (Macronix)
| Gamecard ASIC operation command (0x10)
 
 
|-
 
|-
| 0x1
+
| 1
| 0x1
+
| Lapis
| Set to 3
 
 
|-
 
|-
| 0x2
+
| 2
| 0x1
+
|  
| Set to 1
 
|-
 
| 0x3
 
| 0x1
 
| Padding
 
|-
 
| 0x4
 
| 0x4
 
| Gamecard page count (duplicate)
 
|-
 
| 0x8
 
| 0x1
 
| Gamecard command (0x16 or 0x83)
 
|-
 
| 0x9
 
| 0x4
 
| Gamecard page offset
 
|-
 
| 0xD
 
| 0x3
 
| Gamecard page count
 
|-
 
| 0x10
 
| 0x10
 
| Empty
 
|-
 
| 0x20
 
| 0x20
 
| Command verification value
 
 
|}
 
|}
  
== ReadPage ==
+
== UniqueData ==
Reads Gamecard pages. This command is only available in [[#Gamecard modes|Normal]] and [[#Gamecard modes|Secure]] modes.
+
While presumed to be random, this field actually has some degree of determinism depending on the [[#MakerId|MakerId]].
 
 
The [[#OperationBuffer]] is as follows.
 
  
 +
MakerId 0:
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 750: Line 513:
 
| 0x0
 
| 0x0
 
| 0x1
 
| 0x1
| Gamecard ASIC operation command (0x10)
+
| Type (4 = [[Filesystem_services#MemoryType|T1RomLate]], 8 = [[Filesystem_services#MemoryType|T1RomFast]])
 
|-
 
|-
 
| 0x1
 
| 0x1
 
| 0x1
 
| 0x1
| Set to 3
+
| Line (0x21 for [[Filesystem_services#MemoryType|T1RomLate]], incrementing value for [[Filesystem_services#MemoryType|T1RomFast]])
 
|-
 
|-
 
| 0x2
 
| 0x2
| 0x1
 
| Set to 0
 
|-
 
 
| 0x3
 
| 0x3
| 0x1
+
| Id
| Padding
 
 
|-
 
|-
| 0x4
+
| 0x5
| 0x4
+
| 0x2
| Gamecard page count (duplicate)
+
| X (16-bit coordinate?)
 
|-
 
|-
| 0x8
+
| 0x7
| 0x1
+
| 0x2
| Gamecard command (0x21 or 0x5B)
+
| Y (16-bit coordinate?)
 
|-
 
|-
 
| 0x9
 
| 0x9
 
| 0x4
 
| 0x4
| Gamecard page offset
+
| Random
|-
 
| 0xD
 
| 0x3
 
| Gamecard page count
 
|-
 
| 0x10
 
| 0x10
 
| Empty
 
|-
 
| 0x20
 
| 0x20
 
| Command verification value
 
 
|}
 
|}
  
== Erase ==
+
MakerId 1:
Fully erases a Gamecard's contents. This command is only available in [[#Gamecard modes|Write]] mode.
 
 
 
The [[#OperationBuffer]] is as follows.
 
 
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 801: Line 544:
 
|-
 
|-
 
| 0x0
 
| 0x0
| 0x1
+
| 0x2
| Gamecard ASIC operation command (0x10)
+
| Line (incrementing value)
 
|-
 
|-
| 0x1
+
| 0x2
| 0x1
+
| 0x3
| Set to 1
+
| Id
 
|-
 
|-
| 0x2
+
| 0x5
 
| 0x1
 
| 0x1
| Set to 0
+
|  
 
|-
 
|-
| 0x3
+
| 0x6
 
| 0x1
 
| 0x1
| Padding
+
| Version (0 or 1)
 
|-
 
|-
| 0x4
+
| 0x7
| 0x4
+
| 0x2
| Set to 0
+
|  
|-
 
| 0x8
 
| 0x1
 
| Gamecard command (0x18)
 
 
|-
 
|-
 
| 0x9
 
| 0x9
 
| 0x4
 
| 0x4
| Set to 0
+
| Random
|-
 
| 0xD
 
| 0x2
 
| Set to 0
 
|-
 
| 0xF
 
| 0x1
 
| Set to 0
 
|-
 
| 0x10
 
| 0x10
 
| Empty
 
|-
 
| 0x20
 
| 0x20
 
| Command verification value
 
 
|}
 
|}
  
== ReadParameter ==
+
MakerId 2:
Reads a development Gamecard's parameters. This command is only available in [[#Gamecard modes|Write]] mode.
 
 
 
The [[#OperationBuffer]] is as follows.
 
 
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 857: Line 576:
 
|-
 
|-
 
| 0x0
 
| 0x0
| 0x1
+
| 0x4
| Gamecard ASIC operation command (0x10)
+
| Random
 
|-
 
|-
 +
| 0x4
 
| 0x1
 
| 0x1
| 0x1
+
|  
| Set to 3
 
 
|-
 
|-
| 0x2
+
| 0x5
 
| 0x1
 
| 0x1
| Set to 0
+
|  
|-
 
| 0x3
 
| 0x1
 
| Padding
 
 
|-
 
|-
 +
| 0x6
 
| 0x4
 
| 0x4
| 0x4
+
| Id (ASCII string)
| Set to 1
 
 
|-
 
|-
| 0x8
+
| 0xA
 
| 0x1
 
| 0x1
| Gamecard command (0x19)
+
|  
 
|-
 
|-
| 0x9
+
| 0xB
| 0x4
+
| 0x1
| Set to 0
+
|  
 
|-
 
|-
| 0xD
+
| 0xC
| 0x2
 
| Set to 0
 
|-
 
| 0xF
 
 
| 0x1
 
| 0x1
| Set to 0
+
|  
|-
 
| 0x10
 
| 0x10
 
| Empty
 
|-
 
| 0x20
 
| 0x20
 
| Command verification value
 
 
|}
 
|}
  
== WriteParameter ==
+
== CardId1Mirror ==
Writes a development Gamecard's parameters. This command is only available in [[#Gamecard modes|Write]] mode.
+
This field mirrors bit 5 of the [[Filesystem_services#MemoryType|MemoryType]] field from the [[Filesystem_services#CardId1|CardId1]].
 
 
The [[#OperationBuffer]] is as follows.
 
  
 +
= CardCommand =
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
Line 914: Line 616:
 
| 0x0
 
| 0x0
 
| 0x1
 
| 0x1
| Gamecard ASIC operation command (0x10)
+
| [[#CommandId|CommandId]]
 
|-
 
|-
 
| 0x1
 
| 0x1
| 0x1
 
| Set to 3
 
|-
 
| 0x2
 
| 0x1
 
| Set to 1
 
|-
 
| 0x3
 
| 0x1
 
| Padding
 
|-
 
| 0x4
 
| 0x4
 
| Set to 1
 
|-
 
| 0x8
 
| 0x1
 
| Gamecard command (0x20)
 
|-
 
| 0x9
 
| 0x4
 
| Set to 0
 
|-
 
| 0xD
 
| 0x2
 
| Set to 0
 
|-
 
 
| 0xF
 
| 0xF
| 0x1
+
| CommandData
| Set to 0
 
|-
 
| 0x10
 
| 0x10
 
| Empty
 
|-
 
| 0x20
 
| 0x20
 
| Command verification value
 
 
|}
 
|}
  
== SetKey ==
+
== CommandId ==
Sets the Gamecard's internal key data. This command is only available in [[#Gamecard modes|Secure]] mode.
+
These commands are issued by the Gamecard ASIC to the actual Gamecard using the [[#AsicOperation|OperationData]] passed to [[#SendCardCommand|SendCardCommand]].
  
The [[#OperationBuffer]] is as follows.
+
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"
 
|-
 
|-
! Offset
+
! Value
! Size
 
 
! Description
 
! Description
 
|-
 
|-
| 0x0
+
| 0x6
| 0x1
+
|  
| Gamecard ASIC operation command (0x10)
+
|-
 +
| 0xF
 +
| T1ReadUid
 
|-
 
|-
| 0x1
+
| 0x10
| 0x1
+
| DebugReadId1
| Set to 0
 
 
|-
 
|-
| 0x2
+
| 0x11
| 0x1
+
| DebugReadId2
| Set to 0
 
 
|-
 
|-
| 0x3
+
| 0x12
| 0x1
+
| DebugReadId3
| Padding
 
 
|-
 
|-
| 0x4
+
| 0x13
| 0x4
+
| DebugReadUid
| Set to 0
 
 
|-
 
|-
| 0x8
+
| 0x15
| 0x1
+
| DebugReadCrc
| Gamecard command (0x39)
 
 
|-
 
|-
| 0x9
+
| 0x16
| 0x4
+
| DebugWritePage
| Set to 0
 
 
|-
 
|-
| 0xD
+
| 0x17
| 0x2
+
|  
| Set to 0
 
 
|-
 
|-
| 0xF
+
| 0x18
| 0x1
+
| DebugErase
| Set to 0
 
 
|-
 
|-
| 0x10
+
| 0x19
| 0x10
+
| DebugReadParameter
| Empty
 
 
|-
 
|-
 
| 0x20
 
| 0x20
| 0x20
+
| DebugWriteParameter
| Command verification value
+
|-
|}
+
| 0x21
 
+
| T1ReadPage
== Refresh ==
+
|-
Resets the Gamecard's internal status. This command is only available in [[#Gamecard modes|Secure]] mode.
+
| 0x22
 
+
|  
The [[#OperationBuffer]] is as follows.
 
 
 
{| class="wikitable" border="1"
 
 
|-
 
|-
! Offset
+
| 0x28
! Size
+
| ReadId2
! Description
 
 
|-
 
|-
| 0x0
+
| 0x2E
| 0x1
+
| ForceErase
| Gamecard ASIC operation command (0x10)
 
 
|-
 
|-
| 0x1
+
| 0x30
| 0x1
+
| T1ReadId3
| Set to 2
 
 
|-
 
|-
| 0x2
+
| 0x39
| 0x1
+
| T1SetKey
| Set to 0
 
 
|-
 
|-
| 0x3
+
| 0x56
| 0x1
+
| ReadId1
| Padding
 
 
|-
 
|-
| 0x4
+
| 0x59
| 0x4
+
|  
| Set to 0
 
 
|-
 
|-
| 0x8
+
| 0x5B
| 0x1
+
| ReadPage
| Gamecard command (0xB8)
 
 
|-
 
|-
| 0x9
+
| 0x67
| 0x4
+
| T1ReadId1
| Set to 0
 
 
|-
 
|-
| 0xD
+
| 0x83
| 0x2
+
| T1WritePage
| Set to 0
 
 
|-
 
|-
| 0xF
+
| 0x8A
| 0x1
+
|  
| Set to 0
 
 
|-
 
|-
| 0x10
+
| 0xA5
| 0x10
+
| ReadId3
| Empty
 
 
|-
 
|-
| 0x20
+
| 0xB8
| 0x20
+
| T1Refresh
| Command verification value
 
|}
 
 
 
== ChangeDebugDirect ==
 
Used by [[Filesystem_services#OpenGameCardStorage|OpenGameCardStorage]]. This command is only available in [[#Gamecard modes|Normal]] mode.
 
 
 
The [[#OperationBuffer]] is as follows.
 
 
 
{| class="wikitable" border="1"
 
 
|-
 
|-
! Offset
+
| 0xC4
! Size
+
| T1ReadId2
! Description
 
 
|-
 
|-
| 0x0
+
| 0xE0
| 0x1
+
| ReadInitialData
| Gamecard ASIC operation command (0x10)
 
 
|-
 
|-
| 0x1
+
| 0xE2
| 0x1
+
| ChangeInitialData
| Set to 1
 
 
|-
 
|-
| 0x2
+
| 0xE3
| 0x1
+
| T2ReceiveCertificate
| Set to 0
 
 
|-
 
|-
| 0x3
+
| 0xE4
| 0x1
+
| T2SendSocCertificate
| Padding
 
 
|-
 
|-
| 0x4
+
| 0xE5
| 0x4
+
|  
| Set to 0
 
 
|-
 
|-
| 0x8
+
| 0xE6
| 0x1
+
| T2ReceiveRandomValue
| Gamecard command (0x2E)
 
 
|-
 
|-
| 0x9
+
| 0xE7
| 0xF
+
| T2SendRandomValue
| Unlock password
 
 
|-
 
|-
| 0x18
+
| 0xE8
| 0x8
+
| T2ReceiveDeviceChallenge
| Empty
 
 
|-
 
|-
| 0x20
+
| 0xE9
| 0x20
+
| T2RespondDeviceChallenge
| Command verification value
 
|}
 
 
 
= Modes =
 
Both the Gamecard ASIC and the actual Gamecard can operate in different modes.
 
 
 
== ASIC modes ==
 
{| class="wikitable" border="1"
 
 
|-
 
|-
! Mode
+
| 0xEA
! Name
+
| 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
+
|  
 
|}
 
|}
  
= 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 1,170: Line 784:
 
|-
 
|-
 
| 0x104
 
| 0x104
| 0x4
+
| 0x1
| Unknown (0xFF000000, 0xFFFF0000 or 0xFFFFFF00)
+
| ProductionFirmwareFlag
 +
|-
 +
| 0x105
 +
| 0x1
 +
| DevelopmentFirmwareFlag
 
|-
 
|-
| 0x108
+
| 0x106
| 0x4
+
| 0x1
| Empty
+
| WriterFirmwareFlag
 
|-
 
|-
| 0x10C
+
| 0x107
| 0x4
+
| 0x9
| Empty
+
| Reserved
 
|-
 
|-
 
| 0x110
 
| 0x110
| 0x4
+
| 0x8
| Version (0, 0x1, [4.0.0+] 0x3, [9.0.0+] 0x7, [11.0.0+] 0xF)
+
| [[#FirmwareVersion|FirmwareVersion]]
|-
 
| 0x114
 
| 0x4
 
| Unknown (0x80000000)
 
 
|-
 
|-
 
| 0x118
 
| 0x118
 
| 0x4
 
| 0x4
| Data size
+
| FirmwareSize
 
|-
 
|-
 
| 0x11C
 
| 0x11C
 
| 0x4
 
| 0x4
| Empty
+
| Reserved
 
|-
 
|-
 
| 0x120
 
| 0x120
 
| 0x10
 
| 0x10
| Encrypted data IV/CTR
+
| 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"
 
+
|-
=== ReadFw ===
+
! 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
[9.0.0+] This firmware blob was updated.
+
| IsDevelopment
 
+
|-
[11.0.0+] This firmware blob was updated.
+
| 63
 
+
| IsProduction
=== WriterFw ===
+
|}
Code for writing development Gamecards. Only the normal and write [[#Gamecard modes|Gamecard modes]] are supported.
 
 
 
Found inside [[Filesystem_services|FS]].
 
 
 
=== ReadDevFw ===
 
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]].
 
 
 
[9.0.0+] This firmware blob was updated.
 
 
 
[11.0.0+] This firmware blob was updated.
 
 
 
=== RmaFw ===
 
Code for calling [[#ReadRmaInformation]]. 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.

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.