Insert CRC32 into ROM image such that start up CRC32 value results in constant
Started by 5 years ago●13 replies●latest reply 5 years ago●567 viewsI'm inserting a 32 bit CRC into a ROM image in using the following method: First I link using a custom linker script, setting a custom CRC32 symbol to 0. Over the resulting binary I calculate the CRC32. Then I relink the image again but insert the calculated CRC at this symbol location.
At run time I calculate the CRC over the entire ROM image, including the location where the CRC found at link time is stored. I believe I have read somewhere that using this method (or similar) it is possible that the run time CRC calculation yields a constant value, but I can't find any information anymore about it.
Now inserting the CRC as above does not work. Each time I change the source and recompile the resulting run time CRC is different. So, I'm clearly missing something (location of the CRC in the ROM, maybe it requires some kind of inversion), or I'm just plain mistaken.
As a back up I can insert the CRC at the end of the ROM, and simply not take that part into account when calculating the CRC and o a comparison, but I'm just doubting my sanity. Does anyone have any idea?
Thanks! Vincent
Hi Vincent,
please have a look into the Wikipedia (https://de.wikipedia.org/wiki/Zyklische_Redundanzp...) - in the German page there is a nice example how it works.
In general, as long as you are really using a cyclic redundancy check, and the generator polynomial is the same when for encoding and check, the remainder of the division when performing the check, must be 0.
Regards
-- Solderdot
Hi Solderdot,
Unfortunately my German is a bit rusty. But this seems to confirm that it is possible. Just wondering what I'm doing wrong then.
As a test I created the following Python code:
import binascii import numpy as np vals = np.random.randint(0, 0xFFFFFFFF, 8, dtype=np.uint32) vals[-1] = 0 crc = binascii.crc32(vals.tobytes()) vals[-1] = crc crc = binascii.crc32(vals.tobytes()) print("Is it 0?", crc)
I also reversed the byte order. No difference. it is never 0, or some other constant.
Cheers,
Vincent
Endianness matters --- the way you're doing this, the array endianness needs to be consistent with the way the crc is defined --- as does the way in which the CRC is calculated, namely if zeros are shifted in at the end. This produces a constant for crc2:
import binascii import numpy as np vals = np.random.randint(0, 0xFFFFFFFF, 8, dtype=np.uint32) vals = np.array(vals, dtype=np.dtype('<u4')) crc1 = binascii.crc32(vals[:-1].tobytes()) & 0xffffffff print '%08x' % crc1 vals[-1] = crc1 crc2 = binascii.crc32(vals.tobytes()) & 0xffffffff print '%08x' % crc2
I thought I had covered this kind of stuff in my articles on CRCs (https://www.embeddedrelated.com/showarticle/1188.php and https://www.embeddedrelated.com/showarticle/669.php) but I guess not.
Hi Jason,
Thanks! So from your code example I see what I did wrong. I thought I could set the CRC to 0 first, but it really needs to be appended. Going to modify my linker script to do this.
Cheers,
Vincent
By the way, those are a nice set of articles. You should consider bundeling them into a book or something!
Hmmm, I seem to mem you can't include the CRC field in a CRC calculation - it's a circular issue. Just take the data to be protected, calc the CRC and append at data end. It can include a prior CRC, because to this CRC calc, it's just data.
On the other side: open the file, calc the CRC on the data field then compare to CRC field sent with data. Note, pretty much any changes to the data will yield a different CRC. It'd be a lousy CRC method if it didn't.
Hi CustomSarge,
I can include the custom CRC in the ROM image. First I set the symbol to 0, create binary, calc CRC on binary, then set symbol to resulting crc and regenerate binary. LD can do it.
Cheers, Vincent
You imply you are able to reburn one or two bytes, or you re-write an entire block that includes the new CRC.
Are you able to store the entire image in RAM, calculate CRC with the RAM value == 0, set the RAM cell to the CRC, then burn?
No, sorry for the confusion. Only verification is done runtime. The CRC is actually only calculated when building the image.
I guess, you are right when it comes to calculating the CRC anew - this will be different. However, this is about checking the CRC, and this can be done in two ways:
1) as you suggest, calculate the CRC and compare to the CRC stored in the image. If they match the check is pass.
2) do the CRC calculation including the CRC and check the remainder - if it's 0 the check is pass.
Hello Vincent,
I've used such procedure, but with a CRC16. According to the theory I used, this method was inherited by an old HW mechanism and, in my application, it was a very fast way to have safe data protection.
CRC shall be initialized to a well known value and calculation, done on certain ROM area, terminated with a CRC value calculated with the same algorithm, whenever calculation includes the CRC itself, returns a constant value, used to check data consistency.
But, as jms_nh wrote, data endiannes matters, you should be careful to how your data are accessed from the memory. In my case calculation was done on byte basis.
This is an old article that I kept as a reference
http://www.ganssle.com/articles/acrc.htm
I hope this could be useful to you.
Regards,
Rosa
Hi Rosa,
Thanks for the pointers. Nice article.
Cheers,
Vincent