【原创】关于WinCE中bootloader:nboot/eboot的那点事儿

来源:互联网 发布:cf辅助源码群 编辑:程序博客网 时间:2024/05/21 17:23

预备文章:

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

《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;
} IMAGE_DESCRIPTOR, *PIMAGE_DESCRIPTOR;

这两个相依为命的结构体是扒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的愉快。

原创粉丝点击