Lotus3: Difference between revisions

Created page with "The Gamecard ASIC (known internally as the LOTUS3) is a separate chip on the motherboard responsible for communicating with the Gamecard. = Firmware = Filesystem_servic..."
 
From SendCardSelfRefresh and SendCardReadRefreshStatus
 
(47 intermediate revisions by 2 users not shown)
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]].


= Firmware =
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.
[[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.


= Protocol =
All communication is done using custom MMC_SEND_MANUFACTURER commands.
{| class="wikitable" border="1"
|-
! Value
! Description
|-
| 60
| [[#WriteOperation|WriteOperation]]
|-
| 61
| [[#FinishOperation|FinishOperation]]
|-
| 62
| [[#Sleep|Sleep]]
|-
| 63
| [[#UpdateKey|UpdateKey]]
|}
== 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"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x1
| [[#OperationId|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|WriteOperation]] MMC command.
Additional data buffers are then read/written as pages of 0x200 bytes each, using standard MMC read/write commands.
{| class="wikitable" border="1"
|-
! Value
! Description
|-
| 0x01
| [[#SendFirmware|SendFirmware]]
|-
| 0x02
| [[#ReceiveCertificate|ReceiveCertificate]]
|-
| 0x03
| [[#SendSocCertificate|SendSocCertificate]]
|-
| 0x04
| [[#ReceiveRandomValue|ReceiveRandomValue]]
|-
| 0x05
| [[#SendRandomValue|SendRandomValue]]
|-
| 0x06
| [[#ReceiveDeviceChallenge|ReceiveDeviceChallenge]]
|-
| 0x07
| [[#RespondDeviceChallenge|RespondDeviceChallenge]]
|-
| 0x08
| [[#SendHostChallenge|SendHostChallenge]]
|-
| 0x09
| [[#ReceiveChallengeResponse|ReceiveChallengeResponse]]
|-
| 0x0A
| [[#ChangeModeToSecure|ChangeModeToSecure]]
|-
| 0x0B
| [[#WriteRegister|WriteRegister]]
|-
| 0x0C
| [[#ReadRegister|ReadRegister]]
|-
| 0x0D
| [[#ChangeGcModeToDebug|ChangeGcModeToDebug]]
|-
| 0x0E
| [[#GetCardHeader|GetCardHeader]]
|-
| 0x0F
| [[#ChangeGcModeToSecure|ChangeGcModeToSecure]]
|-
| 0x10
| [[#SendCardCommand|SendCardCommand]]
|-
| 0x11
| [[#EnableCardBus|EnableCardBus]]
|-
| 0x12
| [[#ExchangeRandomValuesInSecureMode|ExchangeRandomValuesInSecureMode]]
|-
| 0x13
| [[#ReadRmaInformation|ReadRmaInformation]]
|-
| 0x14
| [9.0.0+] [[#ChallengeCardExistence|ChallengeCardExistence]]
|}
=== SendFirmware ===
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.
=== SendSocCertificate ===
Signals the Gamecard ASIC to receive the certificate from [[Settings_services#GetGameCardCertificate|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.
[[#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 11: Line 213:
|-
|-
| 0x0
| 0x0
| 0x1
| PageSize
|-
| 0x1
| 0x1
| Direction (0 = Read, 1 = Write)
|-
| 0x2
| 0x1
| Reserved
|-
| 0x3
| 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
| [[XCI#AccCtrl1|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 =
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x4
| CupVersion
|-
| 0x4
| 0x4
| [[Filesystem_services#CardId1|CardId1]]
|-
| 0x8
| 0x100
| 0x100
| RSA-PKCS#1 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)
|}
 
= CardKeyArea =
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
|-
| 0x100
| 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]]
|}
 
[11.0.0+] This is now:
{| 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"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x1
| [[#MakerId|MakerId]]
|-
| 0x1
| 0x1
|
|-
| 0x2
| 0x1
|
|-
| 0x3
| 0xD
| [[#UniqueData|UniqueData]]
|-
| 0x10
| 0x1
| Reserved (always 0)
|-
| 0x11
| 0xB
| Reserved (always all 0xFF)
|-
| 0x1C
| 0x4
| [[#CardId1Mirror|CardId1Mirror]]
|-
| 0x20
| 0x20
| Hash
|}
 
== MakerId ==
{| class="wikitable" border="1"
|-
! 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]].
 
MakerId 0:
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x1
| 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
| 0x4
| Magic ("LAFW")
| 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
|
|-
|-
| 0x104
| 0x9
| 0x4
| 0x4
| Unknown (0xFF000000, 0xFFFF0000 or 0xFFFFFF00)
| Random
|}
 
MakerId 2:
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
|-
| 0x108
| 0x0
| 0x4
| 0x4
|
| Random
|-
|-
| 0x10C
| 0x4
| 0x4
| 0x1
|
|-
| 0x5
| 0x1
|  
|  
|-
|-
| 0x110
| 0x6
| 0x4
| 0x4
| Version (0, 1 or 3)
| 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
| [[#CommandId|CommandId]]
|-
| 0x1
| 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"
|-
! Value
! Description
|-
| 0x6
| SelfRefresh
|-
| 0xF
| T1ReadUid
|-
| 0x10
| DebugReadId1
|-
| 0x11
| DebugReadId2
|-
| 0x12
| DebugReadId3
|-
| 0x13
| DebugReadUid
|-
| 0x15
| DebugReadCrc
|-
| 0x16
| DebugWritePage
|-
| 0x17
|
|-
| 0x18
| DebugErase
|-
| 0x19
| DebugReadParameter
|-
| 0x20
| DebugWriteParameter
|-
|-
| 0x114
| 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
| ReadRefreshStatus
|}
 
= AsicFirmware =
This is the Gamecard ASIC's user firmware (Lotus ASIC Firmware or LAFW) uploaded through the [[#SendFirmware|SendFirmware]] operation.
 
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x100
| RSA-2048 PKCS #1 signature over the firmware (data from 0x100 to 0x7800)
|-
| 0x100
| 0x4
| 0x4
| Unknown (0x80000000)
| Magic ("LAFW")
|-
| 0x104
| 0x1
| ProductionFirmwareFlag
|-
| 0x105
| 0x1
| DevelopmentFirmwareFlag
|-
| 0x106
| 0x1
| WriterFirmwareFlag
|-
| 0x107
| 0x9
| Reserved
|-
| 0x110
| 0x8
| [[#FirmwareVersion|FirmwareVersion]]
|-
|-
| 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
|}
 
== 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)
|-
| 62
| IsDevelopment
|-
| 63
| IsProduction
|}
|}
== Anti-downgrade ==
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.