Spanish Oak 1024k Checksums

In order to Flash a custom tune file a checksum is required on the file. Use this to discuss Checksum Algorithms.
Post Reply
Rollex
Posts: 2
Joined: Sun Aug 11, 2019 1:14 am

Spanish Oak 1024k Checksums

Post by Rollex » Wed Aug 14, 2019 8:15 am

Generic check summing code for the Spanish Oak 1024k processors. These are no doubt the same or similar on other processors.

The hard part is getting the region addresses. If you don't have an A2L you can still figure it out via IDA and some disassembly but saves a lot of time if someone gives your the PPC checksum addresses.

Code: Select all

  public bool ValidateChecksums()
        {
            bool check1 = ValidateChecksum(pcmDefinition.CheckSum1Address, pcmDefinition._CheckSum1AreaAddress);
            bool check2 = ValidateChecksum(pcmDefinition.CheckSum2Address, pcmDefinition._CheckSum2AreaAddress);
            bool check3 = ValidateChecksum(pcmDefinition.CheckSum3Address, pcmDefinition._CheckSum3AreaAddress);
            return (check1 && check2 && check3);
        }

        public bool UpdateChecksums()
        {
            uint calculatedChecksum1 = CalculateChecksum(pcmDefinition.CheckSum1AreaAddress);
            uint calculatedChecksum2 = CalculateChecksum(pcmDefinition.CheckSum2AreaAddress);
            uint calculatedChecksum3 = CalculateChecksum(pcmDefinition.CheckSum3AreaAddress);
            BinaryHelper.WriteBigEndianUInt32(pcmDefinition.CheckSum1Address, calculatedChecksum1, this.rawBinary);
            BinaryHelper.WriteBigEndianUInt32(pcmDefinition.CheckSum2Address, calculatedChecksum2, this.rawBinary);
            BinaryHelper.WriteBigEndianUInt32(pcmDefinition.CheckSum3Address, calculatedChecksum3, this.rawBinary);

            //Revalidate checksums for good measure
            return ValidateChecksums();
        }
        

        public bool ValidateChecksum(uint CheckSumAddress, uint CheckSumAreaAddress)
        {
            uint checksum = BinaryHelper.GetBigEndianUInt32(CheckSumAddress, this.rawBinary);
            uint calculatedChecksum = CalculateChecksum(CheckSumAreaAddress);
            return (calculatedChecksum == checksum);
        }
      
        uint CalculateChecksum(uint CheckSumAreaAddress)
        {
            uint checksumEndAddress = BinaryHelper.GetBigEndianUInt32(CheckSumAreaAddress, this.rawBinary);
            uint checksumStartAddress = BinaryHelper.GetBigEndianUInt32(CheckSumAreaAddress + 4, this.rawBinary);

            if (rawBinary == null) return 0;
            if (checksumStartAddress > rawBinary.Length) return 0;
            if (checksumEndAddress > rawBinary.Length) return 0;

            long checkSum = 0;
            uint length = checksumEndAddress - checksumStartAddress + 1;
            int uintsToCheckSum = (int)(length / 4u);  //Number of uints to checksum
            uint i;
            for (i = 0; i < uintsToCheckSum; i++)
            {
                //Get 4 bytes at this address and sum them
                uint address = (uint)(checksumStartAddress + i * 4u);
                if (address + 3 > rawBinary.Length) return 0;
                checkSum += (long)BinaryHelper.GetBigEndianUInt32(address, rawBinary);
            }

            //if (length is not divisible by 4 then get the remaining bytes
            if (length % 4u != 0u)
            {
                uint address = (uint)(checksumStartAddress + i * 4u);
                uint data = BinaryHelper.GetBigEndianUInt32(address, rawBinary) >> (int)((4u - checksumEndAddress % 4u) * 8u);
                checkSum += data;
            }

            return (uint)checkSum;
        }
      
      public static class BinaryHelper{
         
         public static uint GetBigEndianUInt32(uint address, byte[] bytes)
         {
            uint byte1 = (uint)bytes[(int)address] << 24;
            uint byte2 = (uint)bytes[(int)address + 1] << 16;
            uint byte3 = (uint)bytes[(int)address + 2] << 8;
            uint byte4 = (uint)bytes[(int)address + 3];
            return (byte1 + byte2 + byte3 + byte4);
         }
         
         public static bool WriteBigEndianUInt32(uint address, uint value, byte[] rawBinary)
         {
            if (rawBinary == null) return false;
            if (address + 4 > rawBinary.Length) return false;
            byte byte1 = (byte)(value >> 24);
            byte byte2 = (byte)(value >> 16);
            byte byte3 = (byte)(value >> 8);
            byte byte4 = (byte)(value);
            rawBinary[address] = byte1;
            rawBinary[address + 1] = byte2;
            rawBinary[address + 2] = byte3;
            rawBinary[address + 3] = byte4;
            return true;
         }
      }

Post Reply