转自:http://www.cnblogs.com/mercuryxu/archive/2009/12/18/1627528.html

预备文章:

//-----------------------------------------------------------------------//

S3C2410&&WINCE6.0&&NBOOT

WinCE6.0的EBOOT概要

By: cnblogs-HJB

//-----------------------------------------------------------------------//

nk.bin和nk.nb0文件格式分析

By:Gooogleman

//-----------------------------------------------------------------------//

wince2秒快速启动TOC分析

By:gliethttp

//-----------------------------------------------------------------------//

eboot, TOC,NK 地址跳转的问题

By:CSDN-fan227

//-----------------------------------------------------------------------//

Wince bootloader和内核定制

By:kernel

//-----------------------------------------------------------------------//

2440从NANDFlash启动之bootloader运行以前

By:rightsoft

//-----------------------------------------------------------------------//

NBOOT不能加载CE系统

By:驱动开发网-fishly_0

//-----------------------------------------------------------------------//

Nboot程序详细分析

Nboot和Eboot中的虚拟地址与物理地址的关系

By:昔日之ID:formerman

//-----------------------------------------------------------------------//

【原创】关于WinCE中config.bib的问题

By:Mercury

//-----------------------------------------------------------------------//

好了,下面进入正文。昨天我们一起先看了下config.bib。于是我们就想更进一步。来在仔细研究下到底bootloader是有哪些事儿呢?

于是我们就找了上面的一些文章来看看。首先我们看HJB大牛的文章。文章很清晰的告诉了我们wince6.0下如何操作bootloader,下面我们再说一次,本人非常笨,不多说两边记不住,所以大家就忍受吧。首先系统要运行,需要一个引导程序,在以前有NOR flash,友善系列的开发板就是带NOR这个东东,然后伴随的是有一个vivisuper的loader,这里我们不去细谈这个,现在主流是nandflash,所以,对应的有一个nandflash的boot,我们叫他nboot,那我们再来看ARM,我们拿Samsung这个arm来做例子,在HJB大牛的文章中提及了,ARM自身有一个4K的空间来存储应到程序,所以在上电之后通过一系列的配置,将nboot加载到ARM 4k的空间里去执行,nboot就开始对系统的nandflash,内存,USB等等只要是你想初始化的设备进行一个初始化,这里的初始化程度就看你自己写的初始化程序了,按需所设计。接下来是nboot的重要使命,去叫eboot或者直接叫nk,然后结束自己的生命周期。

这里要特别说的是,在上一篇文章完结后,有个朋友问我nboot怎么去找到nk或者eboot在nandflash里的地址啊?这个问题一下也把我问懵了。百思不得其解,看nboot的程序里面到处都是什么loadaddress,或者是jumpaddress之类的东西,以为那个就是,后来根据以上一些文章的阅读发现,其实那些地址只是SDRAM和ARM直接一个虚拟和实际物理地址。根本不是nandflash里的地址。

那如何去从nandflash里面找到我们要的eboot或者image呢?这个时候被我们忽略的TOC蹦出来了,大叫道那些东西都是我扒的。这个时候我们就仔细来看看gliethttp的文章,关于wince TOC启动的文章,这里gliethttp给我们详细介绍了两个结构体:TOC和_IMAGE_DESCRIPTOR,具体这两个结构体的分析我们这里也贴出来,给这两扒东西的留个纪念,并给出一些注释,注释来自gliethttp,具体如下:

   1:  typedef struct _TOC
   2:   {
   3:  //和CSW中的认证域类似,只用来验证接下去内容的合法
   4:  DWORD     dwSignature;
   5:  //包含image的索引(我的是1)、启动delay时间、ip地址、MAC地址和掩码等
   6:  BOOT_CFG    BootCfg;
   7:  //用来描述3个之多的ce内核image数组,我用的是id[1]
   8:  IMAGE_DESCRIPTOR    id[MAX_TOC_DESCRIPTORS];
   9:   CHAININFO           chainInfo;
  10:  } TOC, *PTOC;          // 512 字节
  11:   
  12:  typedef struct _IMAGE_DESCRIPTOR
  13:   {
  14:      DWORD dwVersion;       //编译时的版本号
  15:      DWORD dwSignature;      //“EBOOT”或“CFSH”等
  16:      UCHAR ucString[IMAGE_STRING_LEN];    
            //描述字符串:如"eboot.nb0"之类
  17:      DWORD dwImageType;      //image的类型nk.nb0为0x04
  18:      DWORD dwTtlSectors;         //image文件用到的NAND的扇区总数
  19:      DWORD dwLoadAddress;     //image加载时的虚拟地址
  20:      DWORD dwJumpAddress;    //image加载完成后的跳转地址
  21:      SG_SECTOR sgList[MAX_SG_SECTORS];    
          //image的段描述,包括起始扇区号和所需扇区数目
  22:      ULONG dwStoreOffset;
  23:  } IMAGE_DESCRIPTOR, *PIMAGE_DESCRIPTOR;
  24:   
  25:   

这两个相依为命的结构体是扒eboot和image的罪魁祸首。他们到底是怎么扒的呢,在gliethttp文中介绍道:并不需要一次性将所有nk.nb0数据都加载到内存,应该按需加载,那就是ce的镜像文件image“按需加载”[“段式加载”]方式,TOC就是用来描述ce内核镜像文件image的xipkernel段核心结构体,我们只需加载核文件xipkernel就能正常启动进入wince界面。

好了,到此为止我们搞清楚了原理了,那内存SDRAM和ARM之间的地址又回到了重要的位置,我们怎么去设定这个地址呢?首先我们可以看下最新的mini2440 nboot的写法,首先是给出几个固定的地址,也就是原始的物理地址和起始地址,一般的情况下大家可以在oemaddrtab_cfg.inc中的对照表中找到SDRAM的地址映射,一般情况下是类似如下的描述:

   1:   DCD     0x80000000, 0x30000000, 64     
   2:   ; 64 MB DRAM BANK 6

 

好了,这完成了第一步,第二步我们来写个比较简单的小程序,如何把虚拟地址转换成实际物理地址呢,这里又回到mini2440的最新5.0代码或者6.0代码中,有一句这样的话,写的很好:

 

   1:  #define VIRTUAL_TO_PHYSICAL(va) ( ( (va>0x8c000000) ? (va-0xc000000) : (va) ) - VA_BASE + _RAM_STARTADDRESS )

这里作出了一个判断,保证了地址的大小。同时也转换了地址。

这样一来我们知道如何在两个地址之间转换了,不过这个事情其实是在内存管理单元没有工作的情况下要用一下。当MMU工作了这个事情按照常理是交给MMU处理了.这些都是后话,我们继续看,有了TOC有了地址转换的工具,那地址到底在哪里呢?

现在我们在来看看gooogleman的文章,做wince开发驱动的应该都会用pb自带的一个命令行,这个是很好用的,有的时候makeimg啊,notepad一个什么文件什么的,很方便,这里gooogleman带我们回忆了一个非常重要,但是又往往被我们忽略的一个命令:viewbin,有了这个东东,我们可以仔细的看看我们要引导的eboot.bin或者nk.bin的起始地址是多少了。方法很简单,直接viewbin nk.bin或者viewbin eboot.bin就可以了。起始地址,长度以及开始位置都列的很清晰,而这些个信息我们在TOC扒的时候已经全然送到他们该送的地方去了,系统自己该JUMP的也就JUMP过去,该Lunch的也就去Lunch过去,最新的会自己Run过去,呵呵这个完全看自己写的了。都是一样,无非是用一个指针指去那个地址,下面给个参考例子,我们就RUN过去,首先定义下怎么个run法:

首先初始化一下我们的run

   1:  #define DOWNLOAD_ADDRESS 0x30138000
   2:  void (*run)(void)=(void (*)(void))(DOWNLOAD_ADDRESS);

 

然后我们通过TOC给run加速,一般是在char ReadImageFromNand(unsigned int dwEntry)这个函数中

   1:   run = (void (*)(void))(pToc->id[dwEntry].dwJumpAddress ? VIRTUAL_TO_PHYSICAL(pToc->id[dwEntry].dwJumpAddress) :

最后我们要在main函数里run起来

   1:  if (run)   run();

这句话说的很好听,如果想跑你就跑吧。

好了。到此为止该run到eboot了就去run eboot了,该run image就去run image了。

这里补充下,其实eboot也是一样,eboot起来也就是去run image,这个看设计的要求来定,理论是一样的。

其他的文章对nboot+eboot+image模式进行了详细的阐述,大家可以自己阅读,这里不对说了。

祝贺大家run的愉快。

posted on 2010-08-08 12:22  jiege  阅读(413)  评论(0编辑  收藏  举报