********************************LoongEmbedded********************************
作者:LoongEmbedded(kandi)
时间:2011.7.31
类别:WINCE bootloader开发
********************************LoongEmbedded********************************
备注:本文基于Real6410开发板,采用的是MLC型的NAND Flash K9G8G08,在此学习下载stepldr阶段的镜像文件block0img.nb0。
Windows CE的开发工具Platform Build编译生成的Windows CE操作系统及Bootloader的镜像文件主要由两种格式类型——以.bin为文件名后缀的记录型镜像文件和以.nb0为后缀的原始型(raw)镜像文件,前者以记录(Record)为单位组织镜像的数据,后者则是镜像在嵌入式系统中运行时的二进制数据快照。
Windows CE镜像文件在文件数据的起始位置都有一个7字节的特征码(magic number),它与镜像文件的格式一一对应如下:
“N000FF\X0A”——BL_IMAGE_TYPE_MANIFEST
“X000FF\X0A”——BL_IMAGE_TYPE_MULTIXIP
“B000FF\X0A”——BL_IMAGE_TYPE_BIN
“S000FF\X0A”——BL_IMAGE_TYPE_SIGNED_BIN
“R000FF\X0A”——BL_IMAGE_TYPE_SIGNED_NB0
无特征码——BL_IMAGE_TYPE_UNKNOWN
其中BL_IMAGE_TYPE_SIGNED_NB0代表原始型镜像文件格式,根据DownloaderImage函数的实现部分,在没有要求较高的安全性的情况下(没有定义宏SECURE_BOOTLOADER,这也是默认的情况),DownloaderImage函数把无特征码的BL_IMAGE_TYPE_UNKNOWN类型也当作原始型镜像来处理。但是在安全性较高的情况下(定义了宏SECURE_BOOTLOADER)无特征码的镜像文件是不应该被Bootloader接受的。
原始型镜像文件的处理方法最简单,BootLoader只需从下载端口中读出全部的镜像数据并且存放到相应的存储位置,而且无需处理校验。原始型镜像文件的数据在物理存储中的起始地址和长度都取决于Manifest数据,因而.nb0型的镜像文件不能单独下载(如果定义了宏SECURE_BOOTLOADER,DownloaderImage函数是支持单独下载的当个nb0文件的。),BootLoader必须先下载作为它的前导属性信息的BL_IMAGE_TYPE_MANIFEST类型的镜像文件。
BL_IMAGE_TYPE_MANIFEST类型的镜像文件的数据是多区段的记录型镜像文件的区段(Region)信息。多区段的镜像,简单地说,就是操作系统或者BootLoader的二进制运行时二进制数据分散在不连续的物理存储区间。Manifest的字面意思是“载货单”,该类型的镜像文件并不是真正的Windows CE操作系统的或者BootLoader的二进制运行时数据,只是供下载多区段型镜像所使用的头信息。由于镜像数据的性质特殊,“N000FF\X0A”——BL_IMAGE_TYPE_MANIFEST类型的镜像文件——也称作Manifest数据——与一般的镜像文件数据的存放位置不同,它使用专门的DowloadManifest型全局变量g_DownloadManifest来存放。
DowloadManifest结构体类型在头文件\PUBLIC\COMMON\OAK\INC\blcommon.h中定义如下:
图1
多区段意味着多文件,即一个操作系统或者BootLoader的二进制运行时数据存放在多个镜像文件中,这多个镜像文件的数据对应于可以连续也可以不连续的多个物理存储区域。DowloadManifest结构体的成员dwNumRegion就是多区段镜像的区段个数,也即是后续多个镜像文件的文件个数。Region数组成员负责具体存放各区段的信息,BL_MAX_BIN_REGIONS在头文件%_WINCEROOT%\PUBLIC\COMMON\OAK\INC\blcommon.h中定义为25,意味着多区段的镜像区段数最大不超过25。Region数组成员的元素类型RegionInfo又是一个在头文件blcommon.h中定义的结构体:
见图1
RegionInfo结构体的3个成员dwRegionStart、dwRegionLength、szFileName含义分别是一个镜像区段在物理存储中的起始地址、以字节为单位的区段长度和与镜像区段相对应的镜像文件名。
对于BL_IMAGE_TYPE_MANIFEST类型的镜像文件,文件数据中紧随7字节的格式类型特征码之后下载端口读出的是4字节的校验数据,继之是4字节的区段个数。区段个数数据理所当然存放在g_DownloaderManifest全局变量的dwNumRegions成员中,随后依次读出的是镜像的g_DownloaderManifest.dwNumRegions个区段的属性数据——起始地址、区段长度、区段数据的镜像文件名,按顺序存放在g_DownloaderManifest.dwNumRegions数组的各个元素中。DownloaderImage函数调用CheckImageManifest函数读取4字节校验数据和随后的全部Manifest数据,然后CheckImageManifest函数调用VerifyChecksum函数对Manifest数据执行校验,不过校验范围仅限于存放在g_DownloaderManifest.Regions数组中的区段头信息的数据,不包括4字节的g_DownloaderManifest.dwNumRegions的数据。
BL_IMAGE_TYPE_MANIFEST类型在所有的镜像文件格式类型中比较另类,它只是供下载其他类型的镜像文件而是用的前导信息,本身并不包含有效的Windows CE操作系统或者BootLoader的二进制运行时数据。如果操作系统的镜像只有一个区段,或者使用自身包含有存储位置等头信息的记录型镜像文件格式,也可以不使用Manifest前导数据。BL_IMAGE_TYPE_MANIFEST类型的镜像文件下载完成以后,DownloaderImage函数并不立即执行返回,还要依据全局变量g_DownloaderManifest中的Manifest数据所提供的信息继续下载装载有真实的操作系统二进制数据的镜像文件。
下面就根据bootloader的代码来学习如何下载block0img.nb0,bootloader的下载主流程函数BootloaderMain的主要部分如下图:
图2
下面就围绕DownloadImage函数和OEMLaunch函数展开学习下载流程。
1. DownloadImage函数
1.1读取镜像文件的Manifest前导数据
图3
1.1.1 GetImageType函数
DownloadImage函数首先调用GetImageType()来获取下载的镜像文件的类型,这个是根据镜像文件的头7个字节的特征码来判断的
图4
1.1.2 OEMReadData函数
我们知道是根据OEMReadData函数来读取镜像文件的数据,因为我们是通过USB来下载数据的,所以是通过调用UbootReadData函数来实现的,下面来分析此函数:
图5
1.1.3 CheckImageManifest函数读取packet校验码、RegionInfo结构体数据及核实packet的校验码
图6
1.2 根据Manifest前导数据读取实际的镜像文件数据
图7
1.2.1 DownloadNB0函数
此函数体第一部分,
图8
1) OEMMultiBINNotify函数
图9
2) OEMVerifyMemory函数
图10
DownloadNB0函数体的第二部分:
图11
到此我们知道下载的block0img.nb0先缓存在RAM的0x80100000开始的地址处,下载NK.bin是一样是缓存在这个地址处,而我们通过图5知道通过USB下载镜像的时候是先下载到RAM的0x83000000开始的地址处,所以我们就只能正常把0x83000000-0x80100000=0x2F00000,也即47MB的镜像文件,如果要下载更大的镜像文件就改大0x83000000,当然了,这时候也要考虑实际用的RAM(在此我们使用mobile DDR)的大小了。
1) OEMMapMemAddr函数
图12
如果目标系统的需求是要能支持把镜像文件下载到FLASH中去,就必须调用本函数。由于FLASH操作速度比RAM慢,在片擦除的时候甚至会使读写操作停滞,而OEMMapMemAddr使用了RAM缓冲镜像文件的方式,使得用户在下载镜像文件时感觉不到停滞,这个函数将FLASH地址映射到RAM地址,这样向FLASH写的数据实际上先被缓冲到RAM中,然后再写到FLASH中。
1.2.2 ComputeChecksum函数
见图7,ComputeChecksum函数是用于对镜像文件的数据计算校验码。
1.2.3 WriteImageToFlash函数
图13
到此DownloadImage函数已介绍完,下面介绍OEMLaunch函数
2. OEMLaunch函数
图14
此部分主要是通过调用WriteRawImageToBootMedia函数把镜像文件写到Flash中。