Subaru:DBW Checksum Algorithm

From OpenECU

Jump to: navigation, search

The DBW Subaru ECUs have a checksum system built into the code which performs a number of checksums on the main flash area. What areas are checksummed and what the checksum results must be are actually defined in the data itself. This article describes how the checksum algorithm works, and how you can fix a flash image to have either the correct checksum, or not be checksummed at all.

The checksum definitions

At address 0x007FB80 (512kB SH7055 ECUs) or 0x00FFB80 (1024kB SH7058 ECUs) there is a table which defines the checksum areas. The structure can be described in C notation as follows (remember that the SH2 is little endian):

   struct
   {
       unsigned int* addr_start;
       unsigned int* addr_end;
       unsigned int checksum_value;
   } checksum_areas[17];

The checksum algorithm

The checksum algorithm is simply to sum the little endian 32-bit values in the address range from addr_start to addr_end, add the checksum_value to the sum, and make sure it equals 0x5AA5A55A. There is also some validation to make sure that the address range is reasonable. The overall algorithm can be written as follows in C notation:

   bool do_checksums()
   {
       int i;
       unsigned int* addr;
       unsigned int sum;
       // loop through all checksum areas
       for (i = 0; i < num_checksum_areas; i++)
       {
           // validate checksum_area[i]
           if ((checksum_areas[i].addr_start % 4) != 0)
               return false;   // must start on 32bit boundary
           if (checksum_areas[i].addr_start > checksum_areas[i].addr_end)
               return false;   // start can't be after end
           if ((checksum_areas[i].addr_end % 4) != 3
               && checksum_areas[i].addr_start != checksum_areas[i].addr_end)
               return false;   // must end on 32bit boundary, or be an empty range

           sum = 0;
           for (addr = checksum_areas[i].addr_start; addr < checksum_areas[i].addr_end; addr++;)
               sum += *addr;

           if (sum + checksum_areas[i].checksum_value != 0x5AA5A55A)
               return false;   // bad checksum!
       }
       return true;    // all areas OK
   }

How to keep the checksum system happy

Note that is valid to have an address range which is simply 0x00000000 to 0x00000000. In this case, the sum will be zero, and checksum_value will need to be 0x5AA5A55A for the checksum to be valid. If you look at the checksum table in flash, you will see that most checksum areas are disabled in this way. So, by simply replacing all entries in the checksum table with 0x00000000 0x00000000 0x5AA5A55A, checksumming can be turned off completely.

Alternatively, one can compute the checksum using the algorithm above, subtract that sum from 0x5AA5A55A, and determine the needed checksum_value.

Personal tools