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
值。