linker generated checksum

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

linker generated checksum

Jump to solution
3,200 Views
electropw
Contributor III

Hi all,

 

Seems like this subject comes around and never seems to get a good answer.

 

Compiler version 5.1 for the HCS12.

 

The documentation for the use of generating firmware checksums via the PRM and storing it in a flash address is not very comprehensive and leaves more questions than answers.

 

I am using the 9sS12A64 device, although I think that matters little. Ideally I want to generate a CRC32 if all 4 flash pages and save the result in a specified flash position. Off cause the chksum location is omitted from the calculation.

 

My PRM setup is as follows:-

 

CHECKSUM
  CHECKSUM_ENTRY METHOD_CRC32
    OF      READ_ONLY   0x3C8000 TO 0x3CBFFF
    OF      READ_ONLY   0x3D8000 TO 0x3DBFFF
    OF      READ_ONLY   0x3e8004 TO 0x3eBFFF  // omit the checksum storage from calc
    OF      READ_ONLY   0x3F8000 TO 0x3FBFFF
    INTO    READ_ONLY   0x4000 SIZE 4
    UNDEFINED 0x3F
  END
END

 

The unused flash bytes in each page have been FILLED with 0x3F, so I think the "UNDEFINED 0x3F" statement is not really needed.

 

It generates a chksum but a manual calculation fails to match. The manual calculation used a std CRC32 calc with a polynomial of 0x04C11DB7 using Big Endian style.

 

Here the documentation is poor and does not define how to implement the CRC32 to match that of the compiler.

It also does not  specify how to define access to the pages for calculation, eg for the top page, the physical address is FC000-FFFFF, or 3F8000-3FBFFF, or C000-FFFF.

 

I decided to experiment as see if the compiler matches the checksum which ever way you use.  So I compiled the same code 3 times, on a single page, using the three different page descriptions and looked at the chksum it produced. I expected it to produce the same chksum each time, as we are looking at the same page each time,  wrong!!!!!!!!

I found the same checksum for the Physical and the Paged methods but the non banked access was different. **bleep**... which one is right???? No wonder I can't get a good checksum.

 

Is it just a waste of time trying to use this auto chksum generation??

Anybody tell me what I'm doing wrong???

 

Living in hope

PhilW

Labels (1)
Tags (1)
0 Kudos
Reply
1 Solution
1,976 Views
kef
Specialist I

I'm trying to say that linker doesn't read your device to calculate checksums. Linker calculates checksum based on the knowledge of what it is putting into binary file.  On device what you see say at nonbanked 0xC000-0xFEFF reads equally the same like what is read from banked addresses 0x3F8000-0x3FBEFF. But linker is not aware about this. It doesn't know that what you allocate to 0xC000 is readable from 0x3F8000! You say to checksum 0x3F8000 and linker ignores what is allocated to 0xC000. So your approach certainly won't work. I just verified it. The same code first checksums 0xC000-0xFeFF, then checksums 0x3F8000-0x3FBeFF. Checksums are the same and match linker calculated checksum, but only in case linker calculates checksum of nonbanked code at 0xC000.

 

  • My checksum definition is not concerned about what segments, banked, unbanked etc are used or defined.

And this is your problem.

Another problem is related to area fill byte. For example vectors area is not included ROM_C000 FILL 0x3F segment, so it is not filled with 0x3F. You should try first to not fill areas and use UNDEFINED 0xFF, which matches erased flash state. Also you should take into account flash security byte. In case your code doesn't define its value, you should skip byte at 0xFF0F from checksum computation.

 

  • I believe that it should blindly calculate the checksum on the defined regions of flash, as defined, providing those

You believe wrong. Support for those linker checksums aware of nonbanked-banked memory shortcuts could be added to the linker, but I fear that it would make linker much less device independant, which is not good, IMO.

 

  • It should also assume that the user has properly filled unused flash bytes to a known value.

This works. But it seems that linker fills only areas, where at least one byte is placed to. Empty unused areas seem to be not filled with byte you specify. This is not hard to workaround, allocating some dummy byte to each area you are going to checksum.

 

  • I have also assumed that the calculation order will be in the order the regions have been defined.

I think this is true

 

  • Unfortunately the documentation is not clear on some of this stuff leaving things very open ended and difficult to get a consistent result.

Yes, I also spent too much time finding init and poly values for CRC32. INIT is 0xffffffff and POLY is 0x04C11DB7.

 

You may find checksum.c and checksum.h in lib\include and lib\src folders of your CW installation. There's tiny topic in the help files how to use these sources. What I found that to calculate checksums of far data areas, you should either edit checksum.* or use large memory model. I guess you don't want to use large memory model. So these steps are recommended

 

1) add -CpPPAGE=0x30 option to compiler command line string

2) add checksum.* to your project.

3) Add

   #undef LIBDEF_FAR_VOID_PTR

   #define LIBDEF_FAR_VOID_PTR 1

lines at the top of your copy of checksum.h

4) in the source code

 

#include <checksum.h> // because of step 3, this include should be last include

                                      // , else you may get some message about redefinitions

 

// list of memory sections to check

const struct __ChecksumArea areas[] =

{

                   // start of area,  size of area

      {(const void * __far)(0xc000), 0x4000-0x100} ,

    {(const void * __far)(0x3f8000), 0x4000-0x100} ,

};

 

 

unsigned long crc;

 

{

   crc = _Checksum_CheckAreasCRC32(areas,

                         sizeof(areas)/sizeof(struct __ChecksumArea)  ,

                       /*poly*/0x04C11DB7        , /*init*/0xFFFFFFFF );

}

 

View solution in original post

0 Kudos
Reply
6 Replies
1,976 Views
kef
Specialist I

I haven't use linker checksums yet, but I would consider one thing. Linker doesn't know anything about how nonpaged flash segments are mapped to banked memory. It is aware only about segments defined in your prm file. And you are trying to just checksum all the banked memory. But in fact on pages 3F and 3E you have allocated also nonbanked segments and linker, I think, is not aware about this.

0 Kudos
Reply
1,976 Views
electropw
Contributor III

Hi, thanks for your response.

 

I don't think I understand what you are trying to say.

 

Maybe I am thinking to simplistically.

My checksum definition is not concerned about what segments, banked, unbanked etc are used or defined.

 

I believe that it should blindly calculate the checksum on the defined regions of flash, as defined, providing those regions are valid according to the rules. One of which I think is not calculating over page boundaries.

It should also assume that the user has properly filled unused flash bytes to a known value.

I have also assumed that the calculation order will be in the order the regions have been defined.

 

Unfortunately the documentation is not clear on some of this stuff leaving things very open ended and difficult to get a consistent result.

 

Now as for my test example it was on the same flash page, firmware unchanged, only changing the PRM flasn region definition of the same page of flash between compilations.

The documentation does not indicate how it should be done. It compiled without issue or warnings on each method.

What is different to referring to the same page in a non banked reference and a banked reference? the contents is the same.

I guess Freescale can only answer this or tell us how it should be done.....

 

PhilW

0 Kudos
Reply
1,977 Views
kef
Specialist I

I'm trying to say that linker doesn't read your device to calculate checksums. Linker calculates checksum based on the knowledge of what it is putting into binary file.  On device what you see say at nonbanked 0xC000-0xFEFF reads equally the same like what is read from banked addresses 0x3F8000-0x3FBEFF. But linker is not aware about this. It doesn't know that what you allocate to 0xC000 is readable from 0x3F8000! You say to checksum 0x3F8000 and linker ignores what is allocated to 0xC000. So your approach certainly won't work. I just verified it. The same code first checksums 0xC000-0xFeFF, then checksums 0x3F8000-0x3FBeFF. Checksums are the same and match linker calculated checksum, but only in case linker calculates checksum of nonbanked code at 0xC000.

 

  • My checksum definition is not concerned about what segments, banked, unbanked etc are used or defined.

And this is your problem.

Another problem is related to area fill byte. For example vectors area is not included ROM_C000 FILL 0x3F segment, so it is not filled with 0x3F. You should try first to not fill areas and use UNDEFINED 0xFF, which matches erased flash state. Also you should take into account flash security byte. In case your code doesn't define its value, you should skip byte at 0xFF0F from checksum computation.

 

  • I believe that it should blindly calculate the checksum on the defined regions of flash, as defined, providing those

You believe wrong. Support for those linker checksums aware of nonbanked-banked memory shortcuts could be added to the linker, but I fear that it would make linker much less device independant, which is not good, IMO.

 

  • It should also assume that the user has properly filled unused flash bytes to a known value.

This works. But it seems that linker fills only areas, where at least one byte is placed to. Empty unused areas seem to be not filled with byte you specify. This is not hard to workaround, allocating some dummy byte to each area you are going to checksum.

 

  • I have also assumed that the calculation order will be in the order the regions have been defined.

I think this is true

 

  • Unfortunately the documentation is not clear on some of this stuff leaving things very open ended and difficult to get a consistent result.

Yes, I also spent too much time finding init and poly values for CRC32. INIT is 0xffffffff and POLY is 0x04C11DB7.

 

You may find checksum.c and checksum.h in lib\include and lib\src folders of your CW installation. There's tiny topic in the help files how to use these sources. What I found that to calculate checksums of far data areas, you should either edit checksum.* or use large memory model. I guess you don't want to use large memory model. So these steps are recommended

 

1) add -CpPPAGE=0x30 option to compiler command line string

2) add checksum.* to your project.

3) Add

   #undef LIBDEF_FAR_VOID_PTR

   #define LIBDEF_FAR_VOID_PTR 1

lines at the top of your copy of checksum.h

4) in the source code

 

#include <checksum.h> // because of step 3, this include should be last include

                                      // , else you may get some message about redefinitions

 

// list of memory sections to check

const struct __ChecksumArea areas[] =

{

                   // start of area,  size of area

      {(const void * __far)(0xc000), 0x4000-0x100} ,

    {(const void * __far)(0x3f8000), 0x4000-0x100} ,

};

 

 

unsigned long crc;

 

{

   crc = _Checksum_CheckAreasCRC32(areas,

                         sizeof(areas)/sizeof(struct __ChecksumArea)  ,

                       /*poly*/0x04C11DB7        , /*init*/0xFFFFFFFF );

}

 

0 Kudos
Reply
1,976 Views
electropw
Contributor III

Thanks Kef,

 

Your a genius!!     :smileyhappy:

 

Your right, the compiler doesn't really know what the final will look like, and what phantoms over what, we just have to make sure we define what it assumes.

So even though we tell the linker to fill unused bytes with say 0x3F it doesn't perform that obviously until after it does the calculation.

 

SO changed it all to not fill unused, set undefine to 0xFF and define the areas of flash to checksum according to what is defined in the PRM.

 

**bleep**, it works.

 

One thing I noticed however is that  the final CRC32 value is not XOR'd with 0xFFFFFFFF. However not to worry I can do that.

 

Thanks again.

PhilW

 

0 Kudos
Reply
1,976 Views
kef
Specialist I

No, linker checksums after area is filled (or is supposed to be filled). But, after some more investigation, I can tell that CW5.1 linker "forgets" to fill unused segments. I mean that if for example you app is small and this segment

 

      PAGE_3D       = READ_ONLY   0x3D8000 TO 0x3DBFFF FILL 0x3F;

 

is not yet used, then linker won't fill this segment at all. But checksum, of course is calculated for all 0x3F.

This is certainly bug. Either checksum should take into account this linkers behaviour, or linker should fill even unused segments. Could you please do service request for this?

0 Kudos
Reply
1,976 Views
electropw
Contributor III

Hi Kef,

 

Sounds like it should have done what I expected.

 

No worries I'll submit one now.

 

Thanks for you input, very much appreciated.

 

PhilW

0 Kudos
Reply