2.3.5 SD卡控制器的相关初始化
一个相关的帖子http://topic.csdn.net/u/20100812/16/d0d5108b-dce1-4535-9e15-6f87bad57e43.html?r=67649425
GPG8---nCD_SD,这个引脚用于判断是否有SD卡存在。
GPH8---WP_SD,这个引脚用于判断SD卡是否lock。
GPE5---SD_CLK
GPE6---SD_CMD
GPE7---SD_DATA0
GPE8---SD_DATA1
GPE9---SD_DATA2
GPE10---SD_DATA3
⑴把GPG8和GPH8设置为输入,以便判断SD卡是否存在?SD卡是否lock?并且把GPE5到GPE10配置为SD卡的功能脚。
⑵初始化SD卡控制器并且初始化并且通过调用函数f_mountdrv来安装文件系统,
SD_card_init()即是初始化SD卡控制器的,在这里就不详细描述这两个函数了。
⑶解析FAT/FAT32格式,找到NK.BIN,并能将其读取到内存中,再假设NK.BIN如下载一般到内存中,将其烧写到nand flash中。
2.3.6显示bootloader更新NK的进度条
2.4 OEMPreDownload (),对于SD卡的更新方式,这里只是根据之前的条件判断当前的动作是正常启动还是要更新NK,在这里应该也可以对bootloader和OS之间共享的数据进行设置。
2.5 DownloadImage()
下图是BootloaderMain函数的主要函数体,也即更新NK并且跳到特定地址启动OS的主要实现部分
这里我们看看DownloadImage函数,主要内容如下:
⑴通过调用函数dwImageType = GetImageType()来获取
调用函数OEMReadData来得到SD卡中映像文件,并且取出这个文件的前面7个字符保存在g_hdr数组中,接下来便判断当前的映像文件是什么类型的。我们要
更新的是NK.bin,我们来看看NK.bin的格式
可以知道NK.bin的头7个字符是B000FF,所以GetImageType函数返回BL_IMAGE_TYPE_SIGNED_BIN值来为后面的更新动作做好准备,我们在这里来看看OEMReadData函数功能:
接下来会调用函数SdMmcReadData
SdMmcReadData函数中的
volatile U32 readLenIndex = SDBUFFER;
#define SDBUFFER 0x32200000
这里SDBUFFER是SDRAM地址,从SD卡从读取到NK就放在以这个地址为开始地址的内存中。
⑵DownloadSignedBin函数,就是download NK的函数。
根据前面得到的image type是BL_IMAGE_TYPE_BIN来执行DownloadImage函数中下面的语句
case BL_IMAGE_TYPE_BIN:
rval &= DownloadBin( pdwImageStart, pdwImageLength, pdwLaunchAddr );
break;
下面来详细学习DownloadBin这个函数的函数体:
①通过调用OEMReadData函数来获取NK.bin的起始地址和长度。
图中串口输出的信息如下
DownloadBin image dwImageStart = 0x80200000, dwImageLength = 0xE82498
②目前我们的bootloader是downloade单个bin。
g_DownloadManifest 的定义如下:
static DownloadManifest g_DownloadManifest;
在这之前bootloader没有对g_DownloadManifest变量的初始化,所以g_DownloadManifest.dwNumRegions的初始值是0.
接着看看DownloadManifest结构体的定义:
从上面的定义可知
dwNumRegions:表示当前要downloade的映像个数,在这里知识download NK.bin,所以dwNumRegions=1.
Region:用来描述某个映像文件的其实地址,长度和这个映像文件的名字,这里描述的
③调用OEMMultiBINNotify函数来提供download的信息给OEM,也即给bootloader
OEMMultiBINNotify的主要函数体如下
上图中第1798行就是把download的NK.bin的信息赋值给bootloader中定义的全局变量g_BINRegionInfo。
④通过调用OEMVerifyMemory函数来判断当前download的NK.bin(也可以downloader eboot.bin等)
下图中第1730和第1731行的宏的定义如下:
//
// Nk Memory reigions defined in config.bib...
//
#define ROM_RAMIMAGE_START 0x80200000
#define ROM_RAMIMAGE_SIZE 0x02300000
这些值是要和files/config.bib下指定的值一直,是用来判断当前要download的NK.bin是否在0x80200000到0x825000000的范围之内,在这里我们这次download的NK.bin信息是:dwImageStart = 0x80200000, dwImageLength = 0xE82498
从而可以知道当前的image type是IMAGE_TYPE_RAMIMAGE。
⑤调用函数OEMReadData来读取NK.bin的内容到SDRAM内存中
每次的读取是以一个record为单位,分别读取这个record的开始地址,长度和校验码,上图的第1128行用于判断当前读取的record是否是最后的一个record,如果是,就退出while循环,也即把整个NK.bin读取到SDBUFFER指向的内存中,所以要保证有足够的内存来保存NK.bin,NK.bin的格式如下:
……………………
在NK.bin文件的最开端,会放置一个BinFile结构,imageStart和ImageLength分别对应镜像展开后在内存中存放的首地址和长度。该结构中的RecordNum为不确定的,通常在最后一个记录之后增加一个address和Chksum都为0的纪录表示结束,而这个表示结束的结构中的Length则标示其实际入口点。
⑥ 调用函数OEMMapMemAddr将FLASH地址映射到RAM地址中。
如果目标系统的需求是要能支持把操作系统的镜像文件下载到FLASH中去,就必须调用本函数。由于FLASH操作速度比RAM慢,在片擦除的时候甚至会使读写操作停滞,这样在每次下载操作系统镜像文件时,由于FLASH的擦写都会使下载停滞。而OEMMapMemAddr使用了RAM缓冲操作系统镜像文件的方式,使得用户在下载操作系统镜像文件时感觉不到停滞,这个函数将FLASH地址映射到RAM地址,这样向FLASH写的数据实际上先被缓冲到RAM中,然后再写到FLASH中。下面是相关帖子的链接:http://topic.csdn.net/u/20091218/11/e56acdfd-23a0-4542-bfac-2364a97fe2e7.html
有必要看看OEMMapMemAddr函数体:
#define CACHED_TO_UNCACHED_OFFSET 0x20000000
#define FILE_CACHE_START (0x80200000 | CACHED_TO_UNCACHED_OFFSET) // Start of file cache (temporary store for flash images).
得到这个cache地址后,就把读出出来的数据块放在这个cache地址处,这个地址就是上面函数注释中提到的file cache location
⑦读出当前的record的数据块并且校验
读取到的数据块就保存在FLASH地址映射的RAM地址lpDest上。
⑧通过查找ROMHDR的地址来计算ROM的偏移量
#define ROM_SIGNATURE_OFFSET 64 //0x40
#define ROM_SIGNATURE 0x43454345 //cece 4byte =>ROMHDR 在0x44偏移处,每个bin 都有个pToc指向ROMHDR开头的地址,看下面的bin 文件结构,在0x44offset处地址里面放的是ROMHDR地址,开始是-1,由romimage.exe来设置的
上图的第1154行主要用于判断当前的NK.bin是否为CE的映像文件。
第1169的串口输出信息是:rom_offset=0x0.
⑨判断当前下载的bin文件是否包含TOC和内核(nk.exe)
第1188行用于判断NK.bin文件中地址为0x80200000+0x40=0x80200040地址处保存的内容是cece,也即是否是WINCE的NK.bin,通过IsKernelRegion函数来判断NK.bin中是否包含有NK.exe,因为有包含,所以通过1194到1196行返回NK.bin的起始地址,长度和跳转地址给DownloadImage函数,下面看IsKernelRegion函数体:
这个函数的串口输出信息如下:
kandi IsKernelRegion dwCacheAddress =0x81080628
TOC的指针地址是0x80200044处,这个地址保存的值就是TOC记录的地址,也即从0x80200044处获取其值(0x81080628),也就知道TOC存放在哪个record上了,在本NK.bin中,是第161个record,可从下面的图片看出来
kandi IsKernelRegion toc copy number =191
kandi IsKernelRegion pROMHeader =0x81080628
kandi IsKernelRegion testTet =0x20
kandi IsKernelRegion plTOC =0x8108067C
0x8108067C-0x81080628=0x54(84),也就是ROMHDR结构体占用的字节数,通过下图的Length=0x00000054也可得知。
第1458行为什么还要加上ROM_SIGNATURE_OFFSET(0x40)呢?因为这从0x8020000到0x8020003F是用于记录NK.bin的开始地址和长度,而加上sizeof(ULONG)是表示0x80200040到0x80200043是用于记录WINCE的“cece”恰好是4个字节,public/common/oal/inc/romldr.h下面的定义可以让我们更清晰去理解:
这里的physfirst address=image start=0x80200000。
第1471行的while用于查询NK.bin中是否包含NK.exe,如果没有就表示此NK.bin没有包含内核,这样的NK.bin就不是所需要的。
上图第1463行的dwNumModules=191,表示NK.bin中包含的模块的数量,包括exe和dll文件,下图是通过viewbin –t nk.bin >aoutput.txt中关于module的内容:
……………………………………………
从上图也可以看出NK.bin中包含的modules是236-46+1,正好是191个,而第一个就是NK.exe
⑶把NK.bin解压到SDRAM中后,接着就计算NK.bin的检验码,并且判读是否马上在DownloadImage函数中把解压后的映像写到flash中。
ComputeChecksum函数计算校验码的原理很简单,就不介绍了,下面看WriteImageToFlash的函数体
串口输出信息如下(换了个NK.bin,所以大小不同啊,哈哈):
Completed file(s):
-----------------------------------
[0]: Address=0x80200000 Length=0xE50694 Name="" Target=RAM
这个函数也很简单,就不介绍了,到此DownloadImage函数的工作就完成了,接着回到BootloaderMain函数中,后面将继续。