S3c2440A平台HIVE注册表+binfs的实现

S3c2440A平台HIVE注册表+binfs的实现

        今天总结一些实现的过程和原理。
        我的例子是基于samsung S3C2440A+samsung ONENAND+WinCE5.0的,开发平台是platform builder 5.0,首先我们基于RAM register的image已经可以正常跑起来了,Flash除了放置image外其他的空间为用户提供文件系统,这部分的驱动程序是用三星的PocetStoreII15。
        先来回味一下底层的东东,我们的Image主要由两部分组成:XIPKERNEL.bin和NK.bin。XIPKERNEL.bin中的东西就是那些WinCE中比较核心的又需要经常加载的一些程序和DLL文件,这些文件会被Boot Loader在刚启动的时候拷贝到RAM中去,这样就可以在RAM中XIP(Excute in place)了。在NK.bin中的基本上是需要但不至于要常驻内存的一些程序和DLL了,比如我们BuildIn下的大部分驱动,比如微软的IE,mediaplayer等应用程序,甚至连设备管理器device.exe也可以放到这里面,这些文件只有在需要的时候才被复制到内存中去执行,节约了内存并且也加快了启动的时间。嘿,到这里大概知道binfs的工作原理和重要性吧。
        binfs的建立工作是在用UT(OEM自己的一种底层的工具集)实现的,UT在烧image的时候会自动把XIPKERNEL和NK分别保存到flash的特定的逻辑扇区上.启动的时候Boot Loader会先把XIPKERNEL复制到RAM中,然后跳到RAM中的XIPKERNEL的入口点去执行,这个时候会跑一些OEMinit之类的CPU,内存,中断等初始化的过程,接着OS会从注册表中找到binfs的一些设置,然后加载binfs的驱动使binfs分区对OS来讲是可用的,假如device.exe是在NK.bin中的话,那么在这个时候就可以用\binfs\device.exe(\binfs是假设的装载路径)来调用它了,如果这个时候binfs没有初始化成功那么,device.exe得不到执行,那么系统肯定就起不来了
        现在来讲讲HIVE,其实HIVE是个很简单的东西,都怪和binfs牵到一起搞得很多问题都走错了方向,本来一天就能搞定结果搞了四五天,NND。这么说吧,WinCE下面就两种注册表,一种是RAM based,另外就是HIVE based了,缺省用的是前者,如果用前者PB会在编译的时候把common.reg和platform.reg的内容做到一个叫reginit.ini的文件然后压缩成default.***(忘记扩展名了,有过老迹象了哈)的文件放到XIPKERNEL中去,image在起来的时候会把这个文件解压到RAM中形成RAM based注册表,既然是RAM based那么所有的改动都会在断电后蒸发,哈哈。怎么办呢?其实再笨你也能想出来,保存到磁盘上不就结了吗!?对你太聪明了,但是你想如果你把注册表全放到磁盘(SDMMC或HDD或Flash)上WinCE怎么在没有加载你磁盘的驱动的情况下读到注册表呢?而一般情况加载磁盘的驱动程序也是要注册表的支持啊!

        嘿,对了,这就是HIVE想到的,看它怎么做,它把注册表分成两部分(其实是三部分,当时大体还是两步分,把user.hv和system.hv做一部分),第一部分就是叫做boot.hv的注册表,里面的东西就是一些在没有拿到保存在磁盘的注册表之前引导时需要的一些设置,这部分的注册表和RAM based的是一样的,改了之后断电就没了,所以这部分的注册表项都是不需要改动的,需要改动的都放到第二部分就是了,这第二部分就是system.hv和user.hv了,也就是一直提到的要放到磁盘上的注册表. 编译的时候PB会根据platform.reg和Common.reg中的标签判断哪些表项放到boot.hv中,这个标签就是;HIVE BOOT SECTION ;END BOOT SECTION,夹在这个标签之间的表项PB在编译的时候会把它们塞到boot.hv中去(boot.hv是二进制文件,要看里面到底放了哪些表项用一个老外写的工具吧,好像叫d_readvol.exe,到google上找得到的),其他的内容会分别塞到default.hv和user.hv中去,最后会把这三个hv文件统统塞到XIPKERNEL中去,这样WinCE在引导的第一阶段就把所有的hv扔到RAM中去了,然后打开boot.hv拿到必要的资料,这其中包括如何加载放置system.hv的磁盘的驱动,所以那些和加载这个磁盘相关的驱动要统统放到boot.hv中,比如FAT文件系统驱动,mspart分区驱动等等,这里有一点很重要就是假如你用binfs而且device.exe在NK.bin中,那么一定在第一阶段要保证binfs可用,否则这里就不可能为system.hv创造条件了。WinCE第一次启动时候磁盘上没有东东,这个时候WinCE会将内存中的default.hv和user.hv复制到注册表BootVars指定的地方,default.hv往往会被重命名为system.hv,第二次启动会先检查磁盘上的hv是不是和内存中的一致,不一致就加载磁盘上的表项。
        整个过程就是这样子,但要注意一点,HIVE注册表也是在内存中运行的,不同的是启动的时候会从磁盘上去读改动的表项,因为这样才能保证速度,所以你做的的注册表改动也是在内存中做的,这个时候如果不将内存中的数值保存到磁盘上那么这些改动还是会丢失的。两种方法来避免丢失,一种是通过应用程序去调用RegFlushKey函数,另一种就是在注册表中将RegistryFlags注册键的值设置为1,让系统在每次被改动后自动保存注册表。

        最后总结一下我到底做了哪些事情:
        1)在PB中将HIVEbased Registers拉到项目的WorkSpaces中来。
        2)把Platform.reg中的下列表项加到boot.hv中
        3)Build Image了
附上我的注册表设置做参考:
;-----------------------------------------------------------------------------------------
;ALL these entries below will be add to boot.hv when hive register is enabled!
;HIVE BOOT SECTION
[HKEY_LOCAL_MACHINE\init\BootVars]
"SYSTEMHIVE"="Documents and Settings\\system.hv"        ;system.hv会保存到\HDD\Documents and Settings\system.hv
"PROFILEDIR"="Documents and Settings"          ;user.hv会保存到\HDD\Documents and Settings\default\user.hv
"Flags"=dword:3                    ;这个应该是wince 5.0下决定在哪个阶段启动device.exe的表项
"DefaultUser"="default"          ;咱们只有一个用户default,基本上就是决定user.hv的路径了
"RegistryFlags"=dword:1        ;这个就是设置注册表每次改动后自动刷新到位于Flash上的system.hv中
;===================================================================
;这个部分是binfs的注册表项,如果你不是用的binfs那么不用将它们拉到boot.hv中

[HKEY_LOCAL_MACHINE\System\StorageManager\AutoLoad\SMFlash]
"DriverPath"="Drivers\\BlockDevice\\SMFlash"
"LoadFlags"=dword:1
"MountFlags"=dword:11
"BootPhase"=dword:0
"Flags"=dword:1000

[HKEY_LOCAL_MACHINE\Drivers\BlockDevice\SMFlash]
"Prefix"="DSK"
"Dll"="BIBDrv.dll"                 ;这个binfs的驱动DLL一定要在XIPKERNEL内部
"Order"=dword:0
"Ioctl"=dword:4
"Profile"="SMFlash"
"FriendlyName"="Samsung Flash Driver"
"MountFlags"=dword:11
"BootPhase"=dword:0
"Flags"=dword:1000
; Bind BINFS to the block driver

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SMFlash]
"DefaultFileSystem"="BINFS"           ;binfs的路径为/BINFS
"PartitionDriver"="mspart.dll"             ;这个分区的驱动DLL一定要在XIPKERNEL内部
"AutoMount"=dword:1
"AutoPart"=dword:1
"MountFlags"=dword:11
"Folder"="ResidentFlash"
"Name"="Samsung Flash Disk"
"BootPhase"=dword:0              ;要在第一阶段加载binfs
"Flags"=dword:1000
"MountHidden"=dword:0            ;有了这个你就可以在/BINFS目录下看到所有的NK.bin的东东了
;===================================================================
;这个部分是设置保存system.hv的磁盘的驱动程序,每个人不一样了,但是大同小异
;我这里用的是PoketStroeII15的Flash驱动,system.hv保存在第一个Flash分区上

IF BSP_POCKETSTORE
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\PocketStore]
"Prefix"="DSK"
"Dll"="ONDisk.dll"                  ;这个是在binfs之后加载,所以可以放在NK.bin中
"Order"=dword:1
"Profile"="PocketStore"
"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
"BmlVolumeId"=dword:0 ; BML volume ID = 0
"BmlPartitionId"=dword:8 ; BML parition ID = PARTITION_ID_FILESYSTEM
"Index"=dword:2
"Flags"=dword:1000                    ;这个flag指定这个驱动只在boot.hv中加载一次

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\PocketStore]
"DefaultFileSystem"="FATFS"
"PartitionDriver"="mspart.dll"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
"MountAsBootable"=dword:1             ;这个是wince 5.0下指定这个分区保存system.hv的关键
"Folder"="HDD"
"Name"="NAND Drive"
"Ioctl"=dword:4
[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\PocketStore\FATFS]
"EnableCacheWarm"=dword:0
ENDIF
;===================================================================
;END HIVE BOOT SECTION
补充:
        我的Flash划分了四个区,第一个区是放4k的只能以nor模式运行的bootloader,然后第二个区放置UT,第三个区放置XIPKERNEL和BINFS,第四个区是将剩下的所有的扇区格式化为一个FAT分区作为文件系统,system.hv就是放置在最后一个分区中,在wince起来之后可以看到有个document and setting文件夹,里面的hv文件都是隐藏的。
        我们用的是三星的ONENAND的flash,其实就是拥有4K NOR的NAND flash,我们的bootloader也分成三部份,第一部分bootloader主要是映射到0x00000000地址的一些跳转指令,这个部分会被烧写到flash的前4K里面,然后三星的ONENAND会自动复制前4K的数据到一个类似NOR的物理模块中,这个NOR模块支持CPU的直接寻址;第二部份叫IPL,它的功能是加载在NAND flash中的image或UT,然后在加载后跳转到其RAM中的入口去执行,因为CPU的数据线和地址线在这个时候还只能直接访问NOR flash,要访问NAND flash的话必须要有NAND的接口驱动,所以在IPL的部分会有NAND的接口驱动的代码,这就导致IPL的代码一般有几十到上百K,我们的flash一个块是128K,前两部分一共占了两个块;第三个部分是UT,就是一些通用的工具,比如烧image,烧bootloader,格式化flash等常用的维护和image升级工具,这个部分的数据最多包括了很多的驱动程序,体积也很大,有300K的样子。
        最后我们的三个部分的bootloader一共占据了flash的头10个块(block),128K*10,但这三个部分在三星的flash的分区中是两个BML分区(三星的flash驱动PocetStoreII里面的概念,你就把它看成普通的磁盘分区好了),等下后面给的图示可以看到。
        接下来的块会放置一个MBR,然后从11个块开始我们放置wince的image了,这个区是第三个BML分区,大小一般在40-200个块左右,因为wince的image也就在4M-20M左右,这些划分分区的工作都是由上面提到的UT去做的,我也没有仔细看源代码,只是看到有BMLFormat之类的函数,其参数就是后面看到的图示。如果是binfs那么这个区会放置两个模块:XIPKERNEL和NK,NK的区域会被binfs的驱动识别并且加载成FAT分区的样子,可以在wince的资源管理器中看到的,具体是怎么被识别的还没有认真的搞懂。
        大概算下来,前面所有的空间也就被占用20多M的样子,剩下的空间了你可以随意利用了,分区的方法还是调用三星的flash驱动中的BMLFormat和STLformat,分区的参数定好了它们就会自动把分区建好,这部分的工作我们在BT中完成的。然后WinCE中仅仅需要将这些分区读出来并显示成磁盘就行了,这个就和SD、HDD的驱动相似了,参考上面的介于“IF BSP_POCKETSTORE”部分的注册表写法就行了。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

WinCE中的Flash分区和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值

你可能感兴趣的:(hive)