Forums

Insert CRC32 into ROM image such that start up CRC32 value results in constant

Started by plinnie 2 months ago13 replieslatest reply 2 months ago54 views

I'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

[ - ]
Reply by SolderdotSeptember 9, 2019

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

[ - ]
Reply by plinnieSeptember 9, 2019

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

[ - ]
Reply by jms_nhSeptember 9, 2019

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.

[ - ]
Reply by plinnieSeptember 9, 2019

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

[ - ]
Reply by plinnieSeptember 10, 2019

By the way, those are a nice set of articles. You should consider bundeling them into a book or something!

[ - ]
Reply by mr_banditSeptember 10, 2019
[ - ]
Reply by CustomSargeSeptember 9, 2019

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.

[ - ]
Reply by plinnieSeptember 9, 2019

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

[ - ]
Reply by mr_banditSeptember 10, 2019

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?

[ - ]
Reply by plinnieSeptember 11, 2019

No, sorry for the confusion. Only verification is done runtime. The CRC is actually only calculated when building the image.

[ - ]
Reply by SolderdotSeptember 10, 2019

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.

[ - ]
Reply by rosignaSeptember 9, 2019

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


[ - ]
Reply by plinnieSeptember 10, 2019

Hi Rosa,

Thanks for the pointers. Nice article.

Cheers,
Vincent