Difference between revisions of "EEPROM"

From xboxdevwiki
Jump to: navigation, search
(Language and value stored in the configuration EEPROM (little endian LeastSigByte at offset 0x90 is the only byte with a non-0x00 value).)
(The HMAC SHA1 Hash: It's not the HMAC HDD Key but the HMAC SHA1 Hash computed across the first 48 bytes which includes the RC4 encrypted HDD Key, etc.)
 
(15 intermediate revisions by 4 users not shown)
Line 22: Line 22:
 
| 0x2F
 
| 0x2F
 
| RC4 Encrypted Region code
 
| RC4 Encrypted Region code
* 0x01 = North America
+
* 0x00000001 = North America
* 0x02 = Japan
+
* 0x00000002 = Japan
* 0x04 = Europe
+
* 0x00000004 = Europe & Australia
 +
* 0x80000000 = Manufacturing plant
 
|-
 
|-
 
| 0x30
 
| 0x30
Line 36: Line 37:
 
| 0x40
 
| 0x40
 
| 0x45
 
| 0x45
| Ethernet MAC address
+
| Ethernet MAC address (Microsoft Xbox - 00:50:F2:xx:xx:xx)
 +
This is the MAC address of the Ethernet hardware, which has been [https://web.archive.org/web/20100617020733/http://standards.ieee.org/regauth/oui/oui_public.txt issued by the IEEE].
 
|-
 
|-
 
| 0x46
 
| 0x46
Line 49: Line 51:
 
| 0x5B
 
| 0x5B
 
| Video Standard
 
| Video Standard
 +
* 0x00000000 = not set (INVALID)
 
* 0x00400100 = NTSC-M
 
* 0x00400100 = NTSC-M
 
* 0x00400200 = NTSC-J
 
* 0x00400200 = NTSC-J
* 0x00800300 = PAL
+
* 0x00800300 = PAL-I
 +
* 0x00400400 = PAL-M
 
|-
 
|-
 
| 0x5C
 
| 0x5C
Line 100: Line 104:
 
| 0x90
 
| 0x90
 
| 0x93
 
| 0x93
| Language ID
+
| Language ID (0 = not set)
* English 0x01 0x00 0x00 0x00
+
* 0x00000001 = English
* Japanese 0x02 0x00 0x00 0x00
+
* 0x00000002 = Japanese
* German 0x03 0x00 0x00 0x00
+
* 0x00000003 = German
* French 0x04 0x00 0x00 0x00
+
* 0x00000004 = French
* Spanish 0x05 0x00 0x00 0x00
+
* 0x00000005 = Spanish
* Italian 0x06 0x00 0x00 0x00
+
* 0x00000006 = Italian
* Korean 0x07 0x00 0x00 0x00
+
* 0x00000007 = Korean
* Chinese 0x08 0x00 0x00 0x00
+
* 0x00000008 = Chinese
* Portuguese 0x09 0x00 0x00 0x00
+
* 0x00000009 = Portuguese
 
|-
 
|-
 
| 0x94
 
| 0x94
 
| 0x97
 
| 0x97
 
| Video Settings
 
| Video Settings
 +
* 0x00080000 = 480p
 +
* 0x00020000 = 720p
 +
* 0x00040000 = 1080i
  
Offset 0x96:
+
* 0x00010000 = Widescreen{{FIXME|reason=What happens if Widescreen and letterbox are enabled at the same time? Can this happen?}}
* 0x??=Normal{{FIXME}}
+
* 0x00100000 = Letterbox{{FIXME|reason=What happens if Widescreen and letterbox are enabled at the same time? Can this happen?}}
* 0xB0=Widescreen
+
 
* 0xB4=Letterbox
+
* 0x00400000 = 60Hz{{FIXME|reason=Unconfirmed; Also, what happens if both refresh rates are disabled?}}
 +
* 0x00800000 = 50Hz{{FIXME|reason=Unconfirmed; Also, what happens if both refresh rates are disabled?}}
 
|-
 
|-
 
| 0x98
 
| 0x98
 
| 0x9B
 
| 0x9B
 
| Audio Settings
 
| Audio Settings
 +
* 0x00000000 = Stereo
 +
* 0x00000001 = Mono
 +
* 0x00000002 = Surround
 +
* 0x00010000 = Enable AC3
 +
* 0x00020000 = Enable DTS
 
|-
 
|-
 
| 0x9C
 
| 0x9C
 
| 0x9F
 
| 0x9F
| Games Parental Control (0 = Max rating) 1 byte at offset 0x9C data 4-byte aligned adds the 3 remaining bytes of 0x00
+
| Games Parental Control (0 = Max rating)
{| class="wikitable"
+
* 0x00000000 = Rating Pending (RP)
! Xbox Game Rating !! EEPROM Value @ 0x9C
+
* 0x00000001 = Adults Only (AO)
|-
+
* 0x00000002 = Mature (M)
| (RP) Rating Pending (Max)
+
* 0x00000003 = Teen (T)
| 0x00
+
* 0x00000004 = Everyone (E)
|-
+
* 0x00000005 = Kids to Adults (K-A)
| (AO) Adults Only
+
* 0x00000006 = Early Childhood (EC)
| 0x01
 
|-
 
| (M) Mature
 
| 0x02
 
|-
 
| (T) Teen
 
| 0x03
 
|-
 
| (E) Everyone
 
| 0x04
 
|-
 
| (K-A) Kids to Adults
 
| 0x05
 
|-
 
| (EC) Early Childhood
 
| 0x06
 
|}
 
 
|-
 
|-
 
| 0xA0
 
| 0xA0
Line 159: Line 155:
 
* 0x3 = {{input-dx-}} or {{input-lx-}}
 
* 0x3 = {{input-dx-}} or {{input-lx-}}
 
* 0x4 = {{input-dx+}} or {{input-lx+}}
 
* 0x4 = {{input-dx+}} or {{input-lx+}}
 +
* 0x5 = {{input-a}}
 +
* 0x6 = {{input-b}}
 
* 0x7 = {{input-x}}
 
* 0x7 = {{input-x}}
 
* 0x8 = {{input-y}}
 
* 0x8 = {{input-y}}
 
* 0xB = {{input-lt}}
 
* 0xB = {{input-lt}}
 
* 0xC = {{input-rt}}
 
* 0xC = {{input-rt}}
* 0 = Disabled{{FIXME|reason=Is this 0x00000000 only, or are shorter codes possible? can a middle section be 0x00 or would that end the sequence?}}
+
* 0x0 = Disabled{{FIXME|reason=Is this 0x00000000 only, or are shorter codes possible? can a middle section be 0x00 or would that end the sequence?}}
  
Note:{{FIXME|reason=Not sure this is the proper place to describe and formatting sucks not used mediawiki that much still learning}}
+
''Note'':
* EEPROM offset 0xA0: <code>23 14 00 00</code>
+
* A passcode 0x00001423 is D-pad directions up (0x1), right (0x4), down (0x2), left (0x3).
* Little Endian value 0x00001423.
+
* Pass code only uses the lower 16 bits; each button is stored as a nibble in the word.  First button in the most significant nibble and last in the least significant nibble.
* The pass code is D-pad directions up (0x1), right (0x4), down (0x2), left (0x3).  
 
* Pass code is only 2 bytes not 4, each button is stored as a nibble in the word.  First button in the most significant nibble and last in the least significant nibble
 
* Data in the EEPROM is aligned to double word (4-byte) boundaries. Thus, the two extra bytes at 0xA2 and 0xA3 of 0x00.
 
 
|-
 
|-
 
| 0xA4
 
| 0xA4
 
| 0xA7
 
| 0xA7
| Movies Parental Control (0 = Max rating) only 1 byte necessary, the 3 remaining bytes for multiple of 4-byte data alignment{{FIXME|reason=Re-word alignment description. The reason for the extra 3 bytes.}}
+
| Movies Parental Control (0 = Max rating)
{| class="wikitable"
+
* 0x00000001 = Adults Only (NC-17)
! Xbox Movie Rating !! EEPROM Value @ 0xA4
+
* 0x00000002 = Restricted (R)
|-
+
* 0x00000004 = Parents Strongly Cautioned (PG-13)
| 8 (Max)
+
* 0x00000005 = Parental Guidance Suggested (PG)
| 0x00
+
* 0x00000007 = General Audiences (G)
|-
 
| 7 (NC-17)
 
| 0x01
 
|-
 
| 6 (R)
 
| 0x02
 
|-
 
| 5
 
| 0x03
 
|-
 
| 4 (PG-13)
 
| 0x04
 
|-
 
| 3 (PG)
 
| 0x05
 
|-
 
| 2
 
| 0x06
 
|-
 
| 1 (G)
 
| 0x07
 
|}
 
 
|-  
 
|-  
 
| 0xA8
 
| 0xA8
Line 226: Line 199:
 
| 0xBF
 
| 0xBF
 
| DVD Playback Kit Zone
 
| DVD Playback Kit Zone
 +
* 0x00000000 = None
 +
* 0x00000001 = Region 1
 +
* ...
 +
* 0x00000006 = Region 6{{FIXME|reason=We should document which regions were actually sold in stores}}
 
|-
 
|-
 
| 0xC0
 
| 0xC0
 
| 0xFF
 
| 0xFF
| Unknown Codes / History ? do not change any values in this region
+
| Unknown Codes / History ? do not change any values in this range
 
|-
 
|-
 
|}
 
|}
Line 246: Line 223:
 
or [https://www.totalphase.com/products/aardvark-i2cspi/ here]), build an [https://www.youtube.com/watch?v=UcK6nKyKGVQ 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 [https://github.com/grimdoomer/PiPROM here] for pinout information. Then use the corresponding software to read/write the EEPROM.
 
or [https://www.totalphase.com/products/aardvark-i2cspi/ here]), build an [https://www.youtube.com/watch?v=UcK6nKyKGVQ 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 [https://github.com/grimdoomer/PiPROM here] for pinout information. Then use the corresponding software to read/write the EEPROM.
  
 +
== The HMAC SHA1 Hash ==
  
==The HMAC HDD Key==
+
The HMAC SHA1 Hash is generated{{FIXME|reason=Stored? Derived? At factory?}} out of the first 48 bytes{{FIXME|reason=..first 48 EEPROM bytes? Encrypted / Decrypted?}}. This section has been identified clearly{{FIXME|reason=What does this mean?}}.
 
 
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:
 
 
 
 
 
{| class="wikitable"
 
|-
 
|  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 [https://web.archive.org/web/20100617020733/http://standards.ieee.org/regauth/oui/oui_public.txt issued by the IEEE].
 
 
 
 
 
==DVD Region==
 
 
 
This DWORD corresponds to the region code for playback of DVD movies:
 
 
 
 
 
{| class="wikitable"
 
|-
 
|  0x00000000
 
|  None
 
|-
 
|  0x00000001
 
|  Region 1
 
|-
 
|  ...
 
|  ...
 
|-
 
|  0x00000006
 
|  Region 6
 
|}
 
  
 
== Checksum Algorithm ==
 
== Checksum Algorithm ==
Line 307: Line 237:
 
   * Rewritten to ANSI C by David Pye (dmp@davidmpye.dyndns.org)
 
   * Rewritten to ANSI C by David Pye (dmp@davidmpye.dyndns.org)
 
   *
 
   *
   * Thanks! */
+
   * Adapted for XboxDevWiki
  void EepromCRC(unsigned char *crc, unsigned char *data, long dataLen) {
+
  */
        unsigned char* CRC_Data = (unsigned char *)malloc(dataLen+4);
+
  uint32_t EepromCRC(unsigned char *data, long dataLen) {
         int pos=0;
+
 
         memset(crc,0x00,4);
+
         // Initialize result to zero
 +
         uint8_t crc[4] = { 0x00, 0x00, 0x00, 0x00 };
 
   
 
   
        memset(CRC_Data,0x00, dataLen+4);
 
 
         //Circle shift input data one byte right
 
         //Circle shift input data one byte right
         memcpy(CRC_Data + 0x01 , data, dataLen-1);
+
        unsigned char* CRC_Data = (unsigned char *)malloc(dataLen + 4);
         memcpy(CRC_Data, data + dataLen-1, 0x01);
+
        memset(CRC_Data, 0x00, dataLen + 4);
 +
         memcpy(CRC_Data + 0x01 , data, dataLen - 1);
 +
         memcpy(CRC_Data, data + dataLen - 1, 0x01);
 
   
 
   
         for (pos=0; pos&lt;4; ++pos) {
+
        // Calculate checksum
 +
         for (unsigned int i = 0; i < 4; i++) {
 
                 unsigned short CRCPosVal = 0xFFFF;
 
                 unsigned short CRCPosVal = 0xFFFF;
                 unsigned long l;
+
                 for (unsigned long l = i; l < dataLen; l += 4) {
                for (l=pos; l&lt;dataLen; l+=4) {
 
 
                         CRCPosVal -= *(unsigned short*)(&amp;CRC_Data[l]);
 
                         CRCPosVal -= *(unsigned short*)(&amp;CRC_Data[l]);
 
                 }
 
                 }
                 CRCPosVal &amp;= 0xFF00;
+
                 CRCPosVal &= 0xFF00;
                 crc[pos] = (unsigned char) (CRCPosVal &gt;&gt; 8);
+
                 crc[i] = (unsigned char) (CRCPosVal >> 8);
 
         }
 
         }
 +
 
         free(CRC_Data);
 
         free(CRC_Data);
 +
 +
        return *(uint32_t*)&crc;
 
  }
 
  }
 
</pre>
 
</pre>
Line 341: Line 276:
 
{
 
{
 
     const uint32_t bitmask = 0xFFFFFFFF;
 
     const uint32_t bitmask = 0xFFFFFFFF;
    const uint32_t num_dwords = section_data_length >> 2;
 
 
     uint64_t checksum = 0;
 
     uint64_t checksum = 0;
 
     uint32_t carry_count = 0;
 
     uint32_t carry_count = 0;
  
     for(uint32_t loop_count = num_dwords; loop_count > 0; loop_count--) {
+
    // Process the data in 32 bit steps
 +
     for(unsigned int i = 0; i < section_data_length / 4; i++) {
 
         checksum += *section_data;
 
         checksum += *section_data;
 
         if(checksum > bitmask) {
 
         if(checksum > bitmask) {
Line 364: Line 299:
  
 
* [https://web.archive.org/web/20040604013125/http://console-dev.com:80/eeprom.htm Information about EEPROM contents]
 
* [https://web.archive.org/web/20040604013125/http://console-dev.com:80/eeprom.htm Information about EEPROM contents]
* [https://github.com/grimdoomer/PiPROM Read/Write an original Xbox EEPROM chip with a Raspberry Pi]
+
* [https://github.com/grimdoomer/PiPROM Read/Write an original Xbox EEPROM chip using a Raspberry Pi]
 +
* [https://mehmedbasic.dk/post/xbox-eeprom/ Read/Write an original Xbox EEPROM using a VGA port]
 
* [https://www.youtube.com/watch?v=UcK6nKyKGVQ How To Make Xbox EEPROM Reader / Write (Video)]
 
* [https://www.youtube.com/watch?v=UcK6nKyKGVQ How To Make Xbox EEPROM Reader / Write (Video)]
 
* [https://www.youtube.com/watch?v=uzrljlHDr9w How To Extract Xbox EEPROM Easy (Video)]
 
* [https://www.youtube.com/watch?v=uzrljlHDr9w How To Extract Xbox EEPROM Easy (Video)]

Latest revision as of 01:22, 20 August 2020

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

Start End Notes
0x00 0x13 HMAC_SHA1 Hash
0x14 0x1B RC4 Encrypted Confounder ??
0x1C 0x2B RC4 Encrypted HDD key
0x2C 0x2F RC4 Encrypted Region code
  • 0x00000001 = North America
  • 0x00000002 = Japan
  • 0x00000004 = Europe & Australia
  • 0x80000000 = Manufacturing plant
0x30 0x33 Checksum2 - Checksum of next 44 (0x2C) bytes (0x34 - 0x5F)*
0x34 0x3F Xbox serial number - (ASCII chars 0x30 - 0x39 to match each digit in SN)
0x40 0x45 Ethernet MAC address (Microsoft Xbox - 00:50:F2:xx:xx:xx)

This is the MAC address of the Ethernet hardware, which has been issued by the IEEE.

0x46 0x47 Unknown Padding ?
0x48 0x57 Online Key ?
0x58 0x5B Video Standard
  • 0x00000000 = not set (INVALID)
  • 0x00400100 = NTSC-M
  • 0x00400200 = NTSC-J
  • 0x00800300 = PAL-I
  • 0x00400400 = PAL-M
0x5C 0x5F Unknown Padding ?
0x60 0x63 Checksum3 - Checksum of the next 92 (0x5C) bytes (0x64 - 0xBF)*
0x64 0x67 Zone Bias - Offset in # minutes to subtract from GMT time

(e.g., for GMT-06 Central; 6hr = 360min = 0x00000168)

0x68 0x6B Standard Timezone Name: 4 characters, NULL fill remainder if shorter (e.g., CST\0, ACST)
0x6C 0x6F Daylight Timezone Name: 4 characters, NULL fill remainder if shorter (e.g., CDT\0, ACDT)
0x70 0x77 Unknown Padding ?
0x78 0x7B Standard Time Starts 10-05-00-02 (Month-Day-DayOfWeek-Hour)
0x7C 0x7F Daylight Savings Time Starts 04-01-00-02 (Month-Day-DayOfWeek-Hour)
0x80 0x87 Unknown Padding ?
0x88 0x8B Standard Timezone Bias; if not DST, 0 (0x00000000) minute time adjust
0x8C 0x8F Daylight Savings Time Bias; if DST, -60 (0xFFFFFFC4) minute time adjust
0x90 0x93 Language ID (0 = not set)
  • 0x00000001 = English
  • 0x00000002 = Japanese
  • 0x00000003 = German
  • 0x00000004 = French
  • 0x00000005 = Spanish
  • 0x00000006 = Italian
  • 0x00000007 = Korean
  • 0x00000008 = Chinese
  • 0x00000009 = Portuguese
0x94 0x97 Video Settings
  • 0x00080000 = 480p
  • 0x00020000 = 720p
  • 0x00040000 = 1080i
  • 0x00010000 = Widescreen[FIXME]
  • 0x00100000 = Letterbox[FIXME]
  • 0x00400000 = 60Hz[FIXME]
  • 0x00800000 = 50Hz[FIXME]
0x98 0x9B Audio Settings
  • 0x00000000 = Stereo
  • 0x00000001 = Mono
  • 0x00000002 = Surround
  • 0x00010000 = Enable AC3
  • 0x00020000 = Enable DTS
0x9C 0x9F Games Parental Control (0 = Max rating)
  • 0x00000000 = Rating Pending (RP)
  • 0x00000001 = Adults Only (AO)
  • 0x00000002 = Mature (M)
  • 0x00000003 = Teen (T)
  • 0x00000004 = Everyone (E)
  • 0x00000005 = Kids to Adults (K-A)
  • 0x00000006 = Early Childhood (EC)
0xA0 0xA3 Parental Control Passcode; 4 button sequence (each key stored in a nibble)
  • 0x1 = Alt=Digital-Pad-Up or Alt=Left-Thumbstick-Up
  • 0x2 = Alt=Digital-Pad-Down or Alt=Left-Thumbstick-Down
  • 0x3 = Alt=Digital-Pad-Left or Alt=Left-Thumbstick-Left
  • 0x4 = Alt=Digital-Pad-Right or Alt=Left-Thumbstick-Right
  • 0x5 = Alt=A button
  • 0x6 = Alt=B button
  • 0x7 = Alt=X button
  • 0x8 = Alt=Y button
  • 0xB = Left-Trigger
  • 0xC = Right-Trigger
  • 0x0 = Disabled[FIXME]

Note:

  • A passcode 0x00001423 is D-pad directions up (0x1), right (0x4), down (0x2), left (0x3).
  • Pass code only uses the lower 16 bits; each button is stored as a nibble in the word. First button in the most significant nibble and last in the least significant nibble.
0xA4 0xA7 Movies Parental Control (0 = Max rating)
  • 0x00000001 = Adults Only (NC-17)
  • 0x00000002 = Restricted (R)
  • 0x00000004 = Parents Strongly Cautioned (PG-13)
  • 0x00000005 = Parental Guidance Suggested (PG)
  • 0x00000007 = General Audiences (G)
0xA8 0xAB XBOX Live IP Address..
0xAC 0xAF XBOX Live DNS Server..
0xB0 0xB3 XBOX Live Gateway Address..
0xB4 0xB7 XBOX Live Subnet Mask..
0xB8 0xBB Other XBLive settings ?
0xBC 0xBF DVD Playback Kit Zone
  • 0x00000000 = None
  • 0x00000001 = Region 1
  • ...
  • 0x00000006 = Region 6[FIXME]
0xC0 0xFF Unknown Codes / History ? do not change any values in this range

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 SHA1 Hash

The HMAC SHA1 Hash is generated[FIXME] out of the first 48 bytes[FIXME]. This section has been identified clearly[FIXME].

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)
  *
  * Adapted for XboxDevWiki
  */
 uint32_t EepromCRC(unsigned char *data, long dataLen) {

         // Initialize result to zero
         uint8_t crc[4] = { 0x00, 0x00, 0x00, 0x00 };
 
         //Circle shift input data one byte right
         unsigned char* CRC_Data = (unsigned char *)malloc(dataLen + 4);
         memset(CRC_Data, 0x00, dataLen + 4);
         memcpy(CRC_Data + 0x01 , data, dataLen - 1);
         memcpy(CRC_Data, data + dataLen - 1, 0x01);
 
         // Calculate checksum
         for (unsigned int i = 0; i < 4; i++) {
                 unsigned short CRCPosVal = 0xFFFF;
                 for (unsigned long l = i; l < dataLen; l += 4) {
                         CRCPosVal -= *(unsigned short*)(&CRC_Data[l]);
                 }
                 CRCPosVal &= 0xFF00;
                 crc[i] = (unsigned char) (CRCPosVal >> 8);
         }

         free(CRC_Data);

         return *(uint32_t*)&crc;
 }

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;
    uint64_t checksum = 0;
    uint32_t carry_count = 0;

    // Process the data in 32 bit steps
    for(unsigned int i = 0; i < section_data_length / 4; i++) {
        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);
}

Further Reading