Changes

Jump to navigation Jump to search
12,199 bytes added ,  14:16, 30 July 2021
Document Wii U drive protocol
Line 5: Line 5:  
== SATA ==
 
== SATA ==
 
The drive is connected to the Wii U via a normal [[Hardware/SATA_Controller|SATA controller]], using AHCI 1.2. The IOSU may communicate with the controller (and, by extension, the drive), though it may need to encrypt the commands with the console-specific drive key from the [[Hardware/SEEPROM|SEEPROM]] before sending them{{check}}. The drive identifies as a standard SATAPI disk drive, connected to port 0. In vWii mode, the AHCI controller is placed into a special compatibility mode, which causes it to emulate the Wii's DI and provide accurate backwards-compatibility for Wii software.
 
The drive is connected to the Wii U via a normal [[Hardware/SATA_Controller|SATA controller]], using AHCI 1.2. The IOSU may communicate with the controller (and, by extension, the drive), though it may need to encrypt the commands with the console-specific drive key from the [[Hardware/SEEPROM|SEEPROM]] before sending them{{check}}. The drive identifies as a standard SATAPI disk drive, connected to port 0. In vWii mode, the AHCI controller is placed into a special compatibility mode, which causes it to emulate the Wii's DI and provide accurate backwards-compatibility for Wii software.
 +
 +
== SCSI Commands ==
 +
Despite using normal SATAPI formatting for its commands (ATA PACKET, etc.), the Wii U disc drive doesn't appear to implement any of the required SCSI commands except for REQUEST SENSE. Instead, an entirely custom set of commands is used. All CDBs appear to be 12 bytes long.
 +
 +
=== 0xDA - ATAPI_DI_READ_DISC_INFORMATION_CMD ===
 +
 +
=== 0xE0 - ATAPI_DI_REQUEST_ERROR_ID_CMD ===
 +
 +
=== 0xED - ATAPI_DI_READ_CBC_CMD ===
 +
 +
=== 0xF1 - ATAPI_CF_AUTHENTICATE_CMD ===
 +
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; border: 1px solid #bbb;" border="1"
 +
! colspan="3" style="padding: 0.2em; background-color: #ddd; text-align: center; font-size: 130%;" | CDB Description
 +
|-
 +
! style="padding: 0.2em; background-color: #ded;" | CDB Offset
 +
! style="padding: 0.2em; background-color: #eee;" | Values
 +
! style="padding: 0.2em; background-color: #edd;" | Description
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 0
 +
| style="padding: 0.2em; background-color: #eee;" | 0xf1
 +
| style="padding: 0.2em; background-color: #edd;" | Opcode
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 1
 +
| style="padding: 0.2em; background-color: #eee;" | 0, 1, 2, 3
 +
| style="padding: 0.2em; background-color: #edd;" | Step (See [[#Authentication]])
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 2-11
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | Padding
 +
|-
 +
| colspan="3" style="padding:0.2em; background-color: #ddf" | Sends or receives 32 bytes depending on stage (See [[#Authentication]])
 +
|}
 +
 +
=== 0xF2 - ATAPI_CF_START_STOP_CMD ===
 +
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; border: 1px solid #bbb;" border="1"
 +
! colspan="3" style="padding: 0.2em; background-color: #ddd; text-align: center; font-size: 130%;" | CDB Description
 +
|-
 +
! style="padding: 0.2em; background-color: #ded;" | CDB Offset
 +
! style="padding: 0.2em; background-color: #eee;" | Values
 +
! style="padding: 0.2em; background-color: #edd;" | Description
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 0
 +
| style="padding: 0.2em; background-color: #eee;" | 0xf2
 +
| style="padding: 0.2em; background-color: #edd;" | Opcode
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 1
 +
| style="padding: 0.2em; background-color: #eee;" | 0, 2, 4, 6, 8, 0xe, 0x16
 +
| style="padding: 0.2em; background-color: #edd;" | Subcommand (see below)
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 2-11
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | Padding
 +
|-
 +
! colspan="3" style="padding: 0.2em; background-color: #eef; text-align: center; font-size: 130%;" | Subcommands
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 0
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Stop unit
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 2
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Awake motor (required for read)
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 4
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Eject
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 6
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Stop unit(?)
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 8
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Unknown
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 0xe
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Load disc
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 0x16
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Run cleaning disc
 +
|}
 +
 +
=== 0xF3 - ATAPI_CF_READ_CMD ===
 +
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; border: 1px solid #bbb;" border="1"
 +
! colspan="3" style="padding: 0.2em; background-color: #ddd; text-align: center; font-size: 130%;" | CDB Description
 +
|-
 +
! style="padding: 0.2em; background-color: #ded;" | CDB Offset
 +
! style="padding: 0.2em; background-color: #eee;" | Values
 +
! style="padding: 0.2em; background-color: #edd;" | Description
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 0
 +
| style="padding: 0.2em; background-color: #eee;" | 0xf3
 +
| style="padding: 0.2em; background-color: #edd;" | Opcode
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 1
 +
| style="padding: 0.2em; background-color: #eee;" | 0, 1, 2, 3
 +
| style="padding: 0.2em; background-color: #edd;" | Subcode (see below)
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 2
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | "cacheLineIndex" (?)
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 3-5
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | Padding
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 6-7
 +
| style="padding: 0.2em; background-color: #eee;" | 0-0xFFFF
 +
| style="padding: 0.2em; background-color: #edd;" | LBA (Block number)
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 8-11
 +
| style="padding: 0.2em; background-color: #eee;" | 0-0xFFFFFFFF
 +
| style="padding: 0.2em; background-color: #edd;" | Block count
 +
|-
 +
! colspan="3" style="padding: 0.2em; background-color: #eef; text-align: center; font-size: 130%;" | Subcodes (retail)
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 0
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Main WUD (0x800 block size)
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 1
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Media titlekey
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 2
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Disc serial
 +
|-
 +
| style="padding: 0.2em; background-color: #eef;" | 3
 +
| colspan="2" style="padding: 0.2em; background-color: #eee;" | Unknown
 +
|-
 +
| colspan="3" style="padding:0.2em; background-color: #ddf" | Response data is encrypted with session key
 +
|}
 +
 +
=== 0xF4 - ATAPI_CF_TEST_UNIT_READY_CMD ===
 +
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; border: 1px solid #bbb;" border="1"
 +
! colspan="3" style="padding: 0.2em; background-color: #ddd; text-align: center; font-size: 130%;" | CDB Description
 +
|-
 +
! style="padding: 0.2em; background-color: #ded;" | CDB Offset
 +
! style="padding: 0.2em; background-color: #eee;" | Values
 +
! style="padding: 0.2em; background-color: #edd;" | Description
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 0
 +
| style="padding: 0.2em; background-color: #eee;" | 0xf4
 +
| style="padding: 0.2em; background-color: #edd;" | Opcode
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 1-11
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | Padding
 +
|-
 +
| colspan="3" style="padding:0.2em; background-color: #ddf" | Command seems to only communicate via error sense codes
 +
|}
 +
 +
=== 0xF5 - ATAPI_CF_INQUIRY_CMD ===
 +
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; border: 1px solid #bbb;" border="1"
 +
! colspan="3" style="padding: 0.2em; background-color: #ddd; text-align: center; font-size: 130%;" | CDB Description
 +
|-
 +
! style="padding: 0.2em; background-color: #ded;" | CDB Offset
 +
! style="padding: 0.2em; background-color: #eee;" | Values
 +
! style="padding: 0.2em; background-color: #edd;" | Description
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 0
 +
| style="padding: 0.2em; background-color: #eee;" | 0xf5
 +
| style="padding: 0.2em; background-color: #edd;" | Opcode
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 1-11
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | Padding
 +
|-
 +
| colspan="3" style="padding:0.2em; background-color: #ddf" | Returns a small struct (see below)
 +
|}
 +
 +
{| class="wikitable"
 +
! colspan="3" | IDENTIFY data
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x00
 +
| 0x02
 +
| Unknown
 +
|-
 +
| 0x02
 +
| 0x01
 +
| Vendor
 +
|-
 +
| 0x03
 +
| 0x01
 +
| Device
 +
|-
 +
| 0x04
 +
| 0x1C
 +
| Unknown
 +
|-
 +
| 0x20
 +
| -
 +
| End
 +
|}
 +
 +
=== 0xF6 - Unknown ATAPI_CF command ===
 +
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; border: 1px solid #bbb;" border="1"
 +
! colspan="3" style="padding: 0.2em; background-color: #ddd; text-align: center; font-size: 130%;" | CDB Description
 +
|-
 +
! style="padding: 0.2em; background-color: #ded;" | CDB Offset
 +
! style="padding: 0.2em; background-color: #eee;" | Values
 +
! style="padding: 0.2em; background-color: #edd;" | Description
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 0
 +
| style="padding: 0.2em; background-color: #eee;" | 0xf6
 +
| style="padding: 0.2em; background-color: #edd;" | Opcode
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 1
 +
| style="padding: 0.2em; background-color: #eee;" | 1 or 2
 +
| style="padding: 0.2em; background-color: #edd;" | Unknown
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 2-11
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | Padding
 +
|-
 +
| colspan="3" style="padding:0.2em; background-color: #ddf" | Checks for dev/retail discs?
 +
|}
 +
 +
=== 0xFB - ATAPI_CF_FREC_READ_CMD ===
 +
{| style="border-collapse: collapse; padding: 0.2em 0.2em 0.2em 0.2em; border: 1px solid #bbb;" border="1"
 +
! colspan="3" style="padding: 0.2em; background-color: #ddd; text-align: center; font-size: 130%;" | CDB Description
 +
|-
 +
! style="padding: 0.2em; background-color: #ded;" | CDB Offset
 +
! style="padding: 0.2em; background-color: #eee;" | Values
 +
! style="padding: 0.2em; background-color: #edd;" | Description
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 0
 +
| style="padding: 0.2em; background-color: #eee;" | 0xfb
 +
| style="padding: 0.2em; background-color: #edd;" | Opcode
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 1
 +
| style="padding: 0.2em; background-color: #eee;" | 0, 2, 0x12
 +
| style="padding: 0.2em; background-color: #edd;" | Subcommand(?)
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 2-3
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | Padding
 +
|-
 +
| style="padding: 0.2em; background-color: #ded;" | 4-11
 +
| style="padding: 0.2em; background-color: #eee;" | 0
 +
| style="padding: 0.2em; background-color: #edd;" | Must sum to 8 or less (subcommand 2 or 0x12 only). IOSU sets byte 4 to 8
 +
|-
 +
| colspan="3" style="padding:0.2em; background-color: #ddf" | 0x20000 bytes response data, encrypted with session key
 +
|}
 +
 +
== Authentication ==
 +
The disc drive uses a two-stage authentication handshake, first a simple [https://en.wikipedia.org/wiki/CBC-MAC CBC-MAC] challenge-response authentication so the console can prove it possesses the correct drive key, and then a function to derive a shared session key. The session key is used to decrypt some response data from the drive, using AES-128-CBC with a null IV.
 +
 +
=== Stage 1: CBC-MAC drive key proof ===
 +
* First, the console requests a challenge from the drive by sending the Authenticate command with a step of 0. The drive responds with 32 random bytes.
 +
* The console then encrypts these bytes using AES-128-CBC and the console drive key, null IV.
 +
* The console takes the ''second'' 16-byte block, which is the CBC-MAC code and appends 16 null bytes.
 +
* The console sends this 32 byte packet to the drive using the Authenticate command with a step of 1.
 +
 +
=== Stage 2: Session key derivation ===
 +
* The console requests the drive's contribution to the session key by sending the Authenticate command with a step of 2. The drive responds with a 32-byte packet - 16 random bytes, then 16 "ee" bytes. If the drive is unhappy with the console's CBC-MAC proof from stage 1, it will instead give a SCSI error.
 +
* The console extracts the 16 random bytes, discarding the "ee"s.
 +
* The console generates 16 random bytes of its own. After verifying these are different to the drive's, it sends them to the drive (along with 16 padding nullbytes) using the Authenticate command with a step of 3.
 +
* The console encrypts both the drive's random bytes and its own random bytes using AES-128-CBC, null IV and the console drive key.
 +
* The console XORs these encrypted sets of bytes together. The result is the 16-bit AES-128 session key.
    
== Cabling ==
 
== Cabling ==

Navigation menu