Difference between revisions of "EEPROM"
Fisherman166 (talk | contribs) (Add read checksum calculation for eeprom reads.) |
KaosEngineer (talk | contribs) (Language and value stored in the configuration EEPROM (little endian LeastSigByte at offset 0x90 is the only byte with a non-0x00 value).) |
||
Line 101: | Line 101: | ||
| 0x93 | | 0x93 | ||
| Language ID | | Language ID | ||
+ | * English 0x01 0x00 0x00 0x00 | ||
+ | * Japanese 0x02 0x00 0x00 0x00 | ||
+ | * German 0x03 0x00 0x00 0x00 | ||
+ | * French 0x04 0x00 0x00 0x00 | ||
+ | * Spanish 0x05 0x00 0x00 0x00 | ||
+ | * Italian 0x06 0x00 0x00 0x00 | ||
+ | * Korean 0x07 0x00 0x00 0x00 | ||
+ | * Chinese 0x08 0x00 0x00 0x00 | ||
+ | * Portuguese 0x09 0x00 0x00 0x00 | ||
|- | |- | ||
| 0x94 | | 0x94 |
Revision as of 07:33, 2 September 2018
The Xbox EEPROM is a 256 byte non-volatile storage device which contains device-specific information. It is connected via I²C and located on address 0x54. Parts of the EEPROM are encrypted using Kernel/XboxEEPROMKey.
Contents
Contents
Note: Info in above table comes from XKUtils XKEEPROM.h.
*Configmagic-FINAL-1.6 uses the wrong size when computing Checksum2 (40 instead of 44 bytes) and Checksum3 (96 instead of 92 bytes). Checksum2 value computed was correct only because the extra 4 bytes not used in the CRC computation were all 0's which does not change the CRC value. However, a similiar problem with computation of Checksum3 is present. The CRC computed for v1.6 Xbox's is incorrect as the 4 extra bytes are not 0's as on earlier versions.
Reading/Writing the EEPROM
Software Method
This is the easiest way to dump an Xbox EEPROM. Use your alternative dashboard to dump the EEPROM to a file and download it over FTP.
Hardware Method
If you cannot dump the EEPROM using software, you can dump it using hardware. You have several options: use an I2C host adapter (see here or here), build an I2C-Serial cable, or use a device like a RaspberryPi which has an I2C interface. Connect SDA/SCL/ground to the LPC pinout on the board. See here for pinout information. Then use the corresponding software to read/write the EEPROM.
The HMAC HDD Key
The HMAC HDD Key is generated out of the first 48 bytes. This section has been identified clearly.
The Region Code
This DWORD is encrypted. It corresponds to the region code in the XBE header:
0x00000001 | North America |
0x00000002 | Japan |
0x00000004 | Europe / Australia |
0x80000000 | Manufacturing plant |
The MAC address
This is the MAC address of the Ethernet hardware, which has been issued by the IEEE.
DVD Region
This DWORD corresponds to the region code for playback of DVD movies:
0x00000000 | None |
0x00000001 | Region 1 |
... | ... |
0x00000006 | Region 6 |
Checksum Algorithm
Checksum2 and Checksum3 values can be calculated by running the following code snippet over the area the checksum covers:
/* The EepromCRC algorithm was obtained from the XKUtils 0.2 source released by * TeamAssembly under the GNU GPL. * Specifically, from XKCRC.cpp * * Rewritten to ANSI C by David Pye (dmp@davidmpye.dyndns.org) * * Thanks! */ void EepromCRC(unsigned char *crc, unsigned char *data, long dataLen) { unsigned char* CRC_Data = (unsigned char *)malloc(dataLen+4); int pos=0; memset(crc,0x00,4); memset(CRC_Data,0x00, dataLen+4); //Circle shift input data one byte right memcpy(CRC_Data + 0x01 , data, dataLen-1); memcpy(CRC_Data, data + dataLen-1, 0x01); for (pos=0; pos<4; ++pos) { unsigned short CRCPosVal = 0xFFFF; unsigned long l; for (l=pos; l<dataLen; l+=4) { CRCPosVal -= *(unsigned short*)(&CRC_Data[l]); } CRCPosVal &= 0xFF00; crc[pos] = (unsigned char) (CRCPosVal >> 8); } free(CRC_Data); }
Read Checksum Algorithm
When the Xbox reads from the FACTORY_SETTINGS or the USER_SETTINGS section of the EEPROM, this algorithm is ran over the entire section accessed (including the CRC checksum mentioned above) to ensure that the data is valid. If the result of the checksum algorithm does not equal 0xFFFFFFFF, STATUS_DEVICE_DATA_ERROR is returned from the Kernel.
static uint32_t eeprom_section_checksum( const uint32_t* section_data, uint32_t section_data_length ) { const uint32_t bitmask = 0xFFFFFFFF; const uint32_t num_dwords = section_data_length >> 2; uint64_t checksum = 0; uint32_t carry_count = 0; for(uint32_t loop_count = num_dwords; loop_count > 0; loop_count--) { checksum += *section_data; if(checksum > bitmask) { carry_count++; checksum &= bitmask; } section_data++; } checksum += carry_count; if(checksum > bitmask) { checksum += 1; } return (uint32_t)(checksum & bitmask); }