From WiiUBrew
< Hardware
Revision as of 12:57, 30 August 2016 by WulfyStylez (talk | contribs) (Haven't seen addr 0x84 mentioned at all, only 0x87 specifically)
Jump to: navigation, search
Latte Registers
Access size32 bits
Byte orderBig Endian
This box: view  talk  edit


The One Time Programmable memory is programmed sometime during the factory process and can never be changed afterwards. The Wii U's OTP is much larger than the Wii's (1KB split across 8 banks of 128 bytes each) and contains an assortment of read-only data, including the console's encryption/decryption keys.

Register List

Latte GPIOs
Address Bits Name Description
0x0d8001ec 32 LT_OTP_COMMAND OTP command
0x0d8001f0 32 LT_OTP_DATA OTP data

General Registers

LT_OTP_COMMAND (0x0d8001ec)
  31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
Access R/W U
Field RD
  15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Access U R/W
Field ADDR
Field Description
RD Set to one to execute a read command. If clear, then the data in LT_OTP_DATA is unchanged.
ADDR Word address to read. 0x00 to 0x1F (32 4byte words) ORed with the bank's number (0x000 to 0x700).

This register contains the command sent to the OTP. It is unknown whether is register is also used during the factory process to program the OTP.

LT_OTP_DATA (0x0d8001f0)
Access R

This register contains the output data for the last issued OTP read command. The execution of a read operation via the LT_OTP_COMMAND register immediately changes this register without any delay.


The Wii U's IOSU interacts with the OTP by setting it's respective Latte registers. In addition to this, the IOS-CRYPTO process is also able to access the OTP indirectly through syscall 0x22, which takes the OTP word index, a buffer to store the result and the requested size as parameters. The IOS-KERNEL then converts the word index:

int read_otp_internal(int index, void* out_buf, u32 size)
  int i_res = disable_interrupts();
  if (size != 0)
    int step = 0;
    while (step < size)
      int word_addr = index + (step >> 2);
      int word_offset = word_addr & 0x1F;      // Each OTP bank has 0x20 * 4 = 0x80 bytes. Valid word indexes go from 0x00 to 0x1F.
      word_addr = word_addr << 3;
      word_offset = word_offset | 0x80000000;  // Set OTP read flag.
      word_addr = word_addr & 0x700;           // OTP bank goes from 0x000 to 0x700.
      word_addr = word_addr | word_offset;
      *(u32*)0x0D8001EC = word_addr;                     // Write to LT_OTPCMD
       u32 temp = *(u32*)0x0D8001EC;                     // Read from LT_OTPCMD (sync?)
      *(u32*)(out_buf + step) = *(u32*)0x0D8001F0;       // Copy from LT_OTPDATA
      step += 4;	
  return 0;
syscall_0x22(index, out_buf, size)
  // Do some permission checks.
  // Internal IOS-KERNEL function.
  read_otp_internal(index, out_buf, size);

OTP Contents

The following things are stored inside the OTP and requested by the IOSU kernel at some point:

Bank Offset (word index * 4) Size Description
0 (Wii bank) 0x000 (0x00 * 4) 0x14 bytes Wii boot1 SHA-1 hash.
0 (Wii bank) 0x014 (0x05 * 4) 0x10 bytes Wii common key.
0 (Wii bank) 0x024 (0x09 * 4) 0x04 bytes Wii NG ID.
0 (Wii bank) 0x028 (0x0A * 4) 0x1D bytes Wii NG private key.
0 (Wii bank) 0x044 (0x11 * 4) 0x14 bytes Wii NAND HMAC (overlaps with NG private key).
0 (Wii bank) 0x058 (0x16 * 4) 0x10 bytes Wii NAND key.
0 (Wii bank) 0x068 (0x1A * 4) 0x10 bytes Wii RNG key.
0 (Wii bank) 0x078 (0x1E * 4) 0x08 bytes Unknown.
1 (Wii U bank) 0x080 (0x20 * 4) 0x04 bytes Security level flag.
Retail: 0x90000000; Debug: 0x88000000; Factory: 0x00000000.
Flag 0x40000000 causes an error in boot0.
Flag 0x80000000 means the console type has been programmed.
Flag 0x00000000 tells boot0 to not crypt or verify ancast images, skip OTP locking, and not require valid SEEPROM info (factory mode).
Flag 0x08000000 tells boot0 to use its first RSA key and debug ancast images (debug mode).
Flag 0x10000000 tells boot0 to use its second RSA key and retail ancast images (retail mode).
If both retail and debug flags are set, boot0 will throw an error.
1 (Wii U bank) 0x084 (0x21 * 4) 0x04 bytes Some flag for IOStrength configurations.
Flag 0x00008000 sets register 0x0D8001E0.
Flags 0x00000008, 0x00000080, 0x00000800, 0x00002000 set register 0x0D8001E4.
Should be 0x00000000 in retail units.
1 (Wii U bank) 0x088 (0x22 * 4) 0x04 bytes Pulse length for SEEPROM manual CLK.
Should be 0x00000000 in retail units (defaults to 0xFA in boot0).
1 (Wii U bank) 0x08C (0x23 * 4) 0x04 bytes Unknown (0x00010000).
1 (Wii U bank) 0x090 (0x24 * 4) 0x10 bytes Wii U Starbuck ancast key.
1 (Wii U bank) 0x0A0 (0x28 * 4) 0x10 bytes Wii U SEEPROM key.
1 (Wii U bank) 0x0B0 (0x2C * 4) 0x10 bytes Unknown.
1 (Wii U bank) 0x0C0 (0x30 * 4) 0x10 bytes Unknown.
1 (Wii U bank) 0x0D0 (0x34 * 4) 0x10 bytes vWii common key.
1 (Wii U bank) 0x0E0 (0x38 * 4) 0x10 bytes Wii U common key.
1 (Wii U bank) 0x0F0 (0x3C * 4) 0x10 bytes Unknown.
2 (Wii U bank) 0x100 (0x40 * 4) 0x10 bytes Unknown.
2 (Wii U bank) 0x110 (0x44 * 4) 0x10 bytes Unknown.
2 (Wii U bank) 0x120 (0x48 * 4) 0x10 bytes Key to encrypt/decrypt SSL RSA key.
2 (Wii U bank) 0x130 (0x4C * 4) 0x10 bytes Key to encrypt seeds for USB storage keys.
2 (Wii U bank) 0x140 (0x50 * 4) 0x10 bytes Unknown.
2 (Wii U bank) 0x150 (0x54 * 4) 0x10 bytes Wii U XOR key.
2 (Wii U bank) 0x160 (0x58 * 4) 0x10 bytes Wii U RNG key.
2 (Wii U bank) 0x170 (0x5C * 4) 0x10 bytes Wii U NAND key.
3 (Wii U bank) 0x180 (0x60 * 4) 0x10 bytes Wii U devkit fallback key.
3 (Wii U bank) 0x190 (0x64 * 4) 0x10 bytes Key to decrypt SEEPROM devkit key.
3 (Wii U bank) 0x1A0 (0x68 * 4) 0x10 bytes Key to encrypt DRH WLAN data.
3 (Wii U bank) 0x1B0 (0x6C * 4) 0x30 bytes Unknown.
3 (Wii U bank) 0x1E0 (0x78 * 4) 0x14 bytes Wii U NAND HMAC.
3 (Wii U bank) 0x1F4 (0x7D * 4) 0x0C bytes Unknown.
4 (Wii U bank) 0x200 (0x80 * 4) 0x10 bytes Unknown.
4 (Wii U bank) 0x210 (0x84 * 4) 0x0C bytes Unknown
4 (Wii U bank) 0x21C (0x87 * 4) 0x04 bytes The USB key seed in SEEPROM must start with this u32.
4 (Wii U bank) 0x220 (0x88 * 4) 0x20 bytes vWii NG private key?
4 (Wii U bank) 0x240 (0x90 * 4) 0x20 bytes Unknown.
4 (Wii U bank) 0x260 (0x98 * 4) 0x10 bytes Wii U RNG seed (only the first 0x04 bytes are used).
4 (Wii U bank) 0x270 (0x9C * 4) 0x10 bytes Unknown.
5 (Wii U bank) 0x280 (0xA0 * 4) 0x04 bytes Wii U/vWii Root-CA version (0x00000012)?
5 (Wii U bank) 0x284 (0xA1 * 4) 0x04 bytes Wii U/vWii Root-CA MS (0x00000003)?
5 (Wii U bank) 0x288 (0xA2 * 4) 0x04 bytes Unknown.
5 (Wii U bank) 0x28C (0xA3 * 4) 0x40 bytes Wii U/vWii Root-CA signature?
5 (Wii U bank) 0x2CC (0xB3 * 4) 0x14 bytes Unknown.
5 (Wii U bank) 0x2E0 (0xB8 * 4) 0x20 bytes Unknown (locked out).
6 (Wii SEEPROM bank) 0x300 (0xC0 * 4) 0x60 bytes Old Wii SEEPROM certificate data.
6 (Wii SEEPROM bank) 0x360 (0xD8 * 4) 0x20 bytes Old Wii SEEPROM signature?
7 (Misc bank) 0x380 (0xE0 * 4) 0x20 bytes Unknown (locked out).
7 (Misc bank) 0x3A0 (0xE8 * 4) 0x10 bytes boot1 key (locked out by boot0).
7 (Misc bank) 0x3B0 (0xEC * 4) 0x10 bytes Unknown (locked out by boot0, not used).
7 (Misc bank) 0x3C0 (0xF0 * 4) 0x20 bytes Empty.
7 (Misc bank) 0x3E0 (0xF8 * 4) 0x10 bytes Unknown.
7 (Misc bank) 0x3F0 (0xFC * 4) 0x0C bytes ASCII tag (unknown meaning).
7 (Misc bank) 0x3FC (0xFF * 4) 0x04 bytes JTAG status.
Set to 0xE1 in retail.
If bit 0x80 is set, JTAG is disabled.