Re: Updating GM EBCM Checksum
Posted: Sat Apr 10, 2021 5:15 am
Looks like I'm going to have to throw in the towel on this one. I don't have nearly enough of an understanding of what it's doing at a conceptual / mathematical level, so I've got no hope of turning it into some kind of script or code.
You'll want to download the attached data sheet to follow along.
The test is run as part of the mode A2 (report programmed status) routine. That subroutine starts at 0x128C. It runs some setup steps and eventually ends up at sub_E88.
sub_128C
>sub_AF8
>>sub_E28
>>>sub_E88
Once it gets to sub_E88, it runs the CRC using the parallel signature analyzer (PSA). It's described in section 8, page 46 of the PDF. In a nutshell, it's a hardware register that updates the CRC every time you do a read from memory.
So sub_E88 initializes that register with 0xFFFFFFFF and then sequentially reads through either the OS or calibration segment, using the start and end addresses found in the headers. Once that's done, it reads the CRC from the flash and compares that to the final result from the PSA register. Based on the result of that comparison, it sets or clears the error flag and then moves on to the rest of its business.
There's some pseudo-code further down the PDF that explains what it's doing. I just can't get my head around it. I found a simplified version of it in this PDF in appendix F (page 50).
https://www.ti.com/lit/ug/spnu501h/spnu ... e.com%252F
I still can't make sense of it. I was able to bang together some Python code that runs a standard CRC32, and I swapped out the poly and init values for what I think the TMS470 is using. It gives the expected result with standard CRC32 values, so I know the code itself works. But I don't get the correct output when I swap in the TMS470 poly and init values. Since I don't understand what it's actually doing, I can't really troubleshoot it. I don't know if my values are wrong, or the Python CRCmod code doesn't operate the same way the TMS470 hardware does. Like the TMS470 isn't a standard CRC or something. Someone who can read the pseudocode could probably answer that question.
There's a couple ways I can think of to get around this. The easiest one (says the guy who can't actually write working code ) would be to write a utility to calculate the correct CRC against the file and flash that as part of your modified calibration. This is a safety critical system, so I'd be in favor of keeping the error checking mechanisms.
It looks like you could maybe disable the calibration region CRC by modifying the last 4 bytes of the OS region header. The A2 routine runs the CRC against the OS region first. Then it checks the last 4 bytes of the OS header to see if there's a pointer to the calibration region. If that value is 0, it sets a pass flag and exits. The problem with that is, you'd need a modified OS with a valid CRC. But you'd only need to do that once, and hopefully never need to mess with the cal CRCs again. This also assumes the system never runs the CRC as a general health check. I haven't disassembled any of the code outside of a couple of diagnostic commands, so I have no idea what happens when it's running in its normal daily life. I do know there are other references to the PSA register address in the main OS code, so it's definitely possible it gets run in other circumstances.
The last thing I can think of is flashing it with your modified calibration, and then running an A2 command. Set up your JTAG adapter with a breakpoint at 0xE98. This is when the CRC routine reads the result of the PSA, but before it runs the compare against the CRC in flash. You could use the JTAG tool halt the processor at that location and manually read out the PSA register (0xFFFFFF40) to see what your processor calculated for the CRC. Then copy that value into your calibration file, reflash it, and see if everything is good to go.
If someone else figures out the math, can you post an explanation? I'd really like to understand this a little better.
You'll want to download the attached data sheet to follow along.
The test is run as part of the mode A2 (report programmed status) routine. That subroutine starts at 0x128C. It runs some setup steps and eventually ends up at sub_E88.
sub_128C
>sub_AF8
>>sub_E28
>>>sub_E88
Once it gets to sub_E88, it runs the CRC using the parallel signature analyzer (PSA). It's described in section 8, page 46 of the PDF. In a nutshell, it's a hardware register that updates the CRC every time you do a read from memory.
So sub_E88 initializes that register with 0xFFFFFFFF and then sequentially reads through either the OS or calibration segment, using the start and end addresses found in the headers. Once that's done, it reads the CRC from the flash and compares that to the final result from the PSA register. Based on the result of that comparison, it sets or clears the error flag and then moves on to the rest of its business.
There's some pseudo-code further down the PDF that explains what it's doing. I just can't get my head around it. I found a simplified version of it in this PDF in appendix F (page 50).
https://www.ti.com/lit/ug/spnu501h/spnu ... e.com%252F
I still can't make sense of it. I was able to bang together some Python code that runs a standard CRC32, and I swapped out the poly and init values for what I think the TMS470 is using. It gives the expected result with standard CRC32 values, so I know the code itself works. But I don't get the correct output when I swap in the TMS470 poly and init values. Since I don't understand what it's actually doing, I can't really troubleshoot it. I don't know if my values are wrong, or the Python CRCmod code doesn't operate the same way the TMS470 hardware does. Like the TMS470 isn't a standard CRC or something. Someone who can read the pseudocode could probably answer that question.
There's a couple ways I can think of to get around this. The easiest one (says the guy who can't actually write working code ) would be to write a utility to calculate the correct CRC against the file and flash that as part of your modified calibration. This is a safety critical system, so I'd be in favor of keeping the error checking mechanisms.
It looks like you could maybe disable the calibration region CRC by modifying the last 4 bytes of the OS region header. The A2 routine runs the CRC against the OS region first. Then it checks the last 4 bytes of the OS header to see if there's a pointer to the calibration region. If that value is 0, it sets a pass flag and exits. The problem with that is, you'd need a modified OS with a valid CRC. But you'd only need to do that once, and hopefully never need to mess with the cal CRCs again. This also assumes the system never runs the CRC as a general health check. I haven't disassembled any of the code outside of a couple of diagnostic commands, so I have no idea what happens when it's running in its normal daily life. I do know there are other references to the PSA register address in the main OS code, so it's definitely possible it gets run in other circumstances.
The last thing I can think of is flashing it with your modified calibration, and then running an A2 command. Set up your JTAG adapter with a breakpoint at 0xE98. This is when the CRC routine reads the result of the PSA, but before it runs the compare against the CRC in flash. You could use the JTAG tool halt the processor at that location and manually read out the PSA register (0xFFFFFF40) to see what your processor calculated for the CRC. Then copy that value into your calibration file, reflash it, and see if everything is good to go.
If someone else figures out the math, can you post an explanation? I'd really like to understand this a little better.