CheckSum是一种用于检查数据文件有没有发生变化的方法,对于一些重要的数据文件为了检查传输过程过程中有没有数据的损坏或丢失,常常会用到CheckSum算法。
WinCE中经常用到CheckSum的地方就是对即将烧写进Flash中的image文件进行校验,和烧写完对写入的数据进行完整性检查,一般这里的image有OSimage和UT的bin文件两种。
CheckSum的原理是把一个文件以二进制的方式打开,将里面所有的字节的值一个一个的累加起来,一直到最后一个字节,最后得到一个累加值,它就是我们要的CheckSum的结果。从CheckSum的这个特性可知数据值为0的字节是不会影响到最终的结果,这种特性我认为也是CheckSum的一个弱点,不能像MD5,SHA1等摘要算法一样基本上能反映出哪怕一个bit的改动,但是这个特性也给WinCE运行期间计算保存在FLASH上的image数据文件的完整性带来了方便。
为了从Flash中得到正确的CheckSum值必须先了解image在Flash中的烧写方式,这包括了解image文件内部是怎么组织的,Flash的分区和块的分配是如何进行的。
先以Sumsung的FLASH为例来分析一下Flash的分区大体原则:
WinCE的Flash分区大体分为Nand BootLoader(NBL)区,Binfs区和文件区,NBL区存放BootLoader和烧写Image的工具程序,Binfs分区存放MBR、image的XIPKERNEL.bin、Chain.bin和NK.bin等OS的数据。文件区一般格式化为FAT分区让WinCE上层的磁盘和分区管理程序管理。Flash的分区是由UT在烧入image的时候决定的,包括每个分区的起止块地址,分区的大小和类型等,Detail如下:
1)NBL区一般占10个块(128K/块)的大小,分区虽小但是却是最重要的部分,保存着UT的三大模块:NBL1(bootloader),NBL2(IPL,Init Program Loader)和NBL3(Upgrade Tools),其中NBL1和NBL2共同保存在FlASH的第一个block中,FLASH芯片在生产的时候厂商都会特别保障这些block的可靠性,特别是保存了最开始bootloader代码和IPL的第一块。按经验来讲,NBL的三个模块加起来一共大约400多K,其占用的10块的block=128K×10 byte的空间大部分是空余的,为了下面叙述方便,这里假设NBL3_END_BLCOK为NBL的最后的block编号。
2)Binfs分区紧接着BL分区,即CE_START_BLOCK=NBL3_END_BLCOK+1,然后一般会将Binfs分区的第一个块存放MBR,MBR在这里仅仅是个标志,不像PC的硬盘中的MBR主要用来保存分区表的信息和引导代码。所以Binfs分区中保存OS数据的起止block范围为CE_START_BLOCK+1到CE_START_BLOCK+CE_MAX_BLOCK为止,我接触的项目中其大小一般为250个块左右,大约等于30Mbytes,WinCE的image一般不会超过这个大小,如果需要可以在分区时加大它的大小。
3)Flash的文件分区就是将剩下的block模拟成为和硬盘,CF卡类似的块设备让WinCE加载成盘符使用。
现在回到正题:如何计算CheckSum。
1)UT的CheckSum计算
UT的bin文件是由bootloader.bin(NBL1),IPL.bin(NBL2)和UpgradeTools.bin(NBL3)这三文件打成的一个封包,然后用PC上的checksum工具计算出checksum值,我们的目的就是在WinCE起来后用AP能通过读Flash的NBL的三个分区并实时计算到这个值。
UT的bin文件最后会被完整的烧写到NAND Flash的编号为0到NBL3_END_BLCOK的block中(虽然会被分为三块烧,但是数据是完整的),具体占用多少block由bin文件的大小决定,剩余的空间会以0填满。虽然不知道bin文件具体的结尾的位置,但是知道剩余空间填0的这个特性后,我们就可以直接调用NAND Flash的驱动程序,而且可以使用轻量级的不带坏块管理的驱动代码直接去读0到NBL3_END_BLCOK的所有数据,然后把每个byte累加起来就能得到CheckSum的值了。
2)IMG的CheckSum计算
大家都知道,如果定义了MultiXIP region的话,WinCE的image用romimage编译出来会生成多个bin文件,这里假设我们在配置image的bib文件中定义了两个region:XIPKernel和NK,那么在执行romimage ce.bib 之后我们会得到XIPKernel.bin,NK.bin,Chain.bin三个文件,最后调用makebinfs生成一个ceimgb.nb0的image镜像文件,我们也会先用CheckSum工具对ceimgb.nb0进行运算得到其完整的CheckSum值。
烧写的过程和UT有两点不同:1)烧写内容选择上,UT的bin文件的所有数据会被烧入Flash,而IMG的镜像文件包含了一些不需要烧入的头信息,所以可能导致烧入Flash的数据不完整;2)烧写使用的NAND Flash的函数不一样,因为IMG烧写在FLASH中的位置位于普通的不受特殊保护的块区,所以要考虑到坏块的管理,所以在调用具体的读写接口的时候要使用较高一层的代码,拿samsung的flash驱动PoketStoreII为例,烧写UT时用的读写函数为NF_ReadPage ,而烧写IMG镜像使用的时STL_Read/Write。
第一个不同点决定了我们如果要能计算得到正确的IMG的CheckSum值则必须将没有烧入到Flash中的ceimgb.nb0的头部数据烧写到为保存IMG预留的并且没有被占用的Flash中,比如IMG预留空间的最后一块,块号为CE_START_BLOCK+CE_MAX_BLOCK。我们通过修改烧写IMG的代码,在烧写完IMG的三个bin的数据后把从0x0到0x248(记不太清楚,大概)的数据写到块CE_START_BLOCK+CE_MAX_BLOCK中。这样的话因为其他的空余空间被0填充,我们就可以调用STL_READ把从CE_START_BLOCK+1(+1是为了略过MBR块)到CE_START_BLOCK+CE_MAX_BLOCK数据全读取出来并且累加得到最后的CheckSum值。