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: | ||
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. | |||
[[Filesystem_services|FS]] | |||
= 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 | ||
| | | [[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 | |||
|- | |- | ||
| | | 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 | ||
| | | 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 | | 0x4 | ||
| | | Random | ||
|} | |||
MakerId 2: | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |- | ||
| | | 0x0 | ||
| 0x4 | | 0x4 | ||
| | | Random | ||
|- | |- | ||
| 0x4 | | 0x4 | ||
| 0x1 | |||
| | |||
|- | |||
| 0x5 | |||
| 0x1 | |||
| | | | ||
|- | |- | ||
| | | 0x6 | ||
| 0x4 | | 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 | |||
| [[#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 | |||
|- | |- | ||
| | | 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 | ||
| | | Magic ("LAFW") | ||
|- | |||
| 0x104 | |||
| 0x1 | |||
| ProductionFirmwareFlag | |||
|- | |||
| 0x105 | |||
| 0x1 | |||
| DevelopmentFirmwareFlag | |||
|- | |||
| 0x106 | |||
| 0x1 | |||
| WriterFirmwareFlag | |||
|- | |||
| 0x107 | |||
| 0x9 | |||
| Reserved | |||
|- | |||
| 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) | |||
|- | |||
| 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. |