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 | |
0x10 | ReadId1Write |
0x11 | ReadId2Write |
0x12 | ReadId3Write |
0x13 | |
0x15 | ReadCrc |
0x16 | WritePage |
0x17 | |
0x18 | Erase |
0x19 | ReadParameter |
0x20 | WriteParameter |
0x21 | ReadPageSecure |
0x28 | ReadId2 |
0x2E | ChangeDebugDirect |
0x30 | ReadId3Secure |
0x39 | SetKey |
0x56 | ReadId1 |
0x59 | |
0x67 | ReadId1Secure |
0x5B | ReadPage |
0x83 | WritePageSecure |
0x8A | |
0xA5 | ReadId3 |
0xB8 | Refresh |
0xC4 | ReadId2Secure |
0xE0 | ReadInitialData |
0xE2 | ChangeInitialData |
0xE3 | |
0xE4 | |
0xE5 | |
0xE6 | |
0xE7 | |
0xE8 | |
0xE9 | |
0xEA | |
0xEB | |
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.