预备文章
//-----------------------------------------------------------------------//
By:昔日之ID:formerman
//-----------------------------------------------------------------------//
By:WE-HJB
//-----------------------------------------------------------------------//
《【原创】关于WinCE中bootloader:nboot/eboot的那点事儿》
By:Mercury
//-----------------------------------------------------------------------//
补充资料
http://download.csdn.net/source/1929962 学习文档附属资料.包括所有的代码和文档
阅读完了上面一些达人的文章以及我的那两片恶搞的文章,大家应该对nboot有个大概的了解.
下面我们再来一起看看nboot.有描述不对的地方如果大家看出来请给予指出.多谢了!!
先以mini2440不带eboot的wince5.0的nboot程序为例,首先我们从文件上来看看nboot大概的一个轮廓:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//第一部分:地址定义
244X_addr.h
244X_addr.inc
这个部分主要是根据samsung的手册,对相应的寄存器定制进行一个定义的工作,同时在244X_addr.inc中有一句比较重要话
1: GBLL BIG_ENDIAN__
2: BIG_ENDIAN__ SETL {FALSE} ;采用little_endian
这句话给出了系统的模式,有的习惯叫成大端和小端模式.具体关于大端小端模式简单的来说用下面一个图就可以解释清楚了:
Big Endian
低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 12 | 34 | 56 | 78 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Little Endian
低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 78 | 56 | 34 | 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。
说句题外话,这里有个小程序大家可以试试,用来测试MCU是大端还是小端
1: u8 checkCPU( )
2: {
3: {
4: union w
5: {
6: u8 a;
7: u16 b;
8: } c;
9: c.a=0;
10: c.b = 1;
11: return (u8)(c.a!=0?1:0);
12: }
13: }
ARM920T can treat words in memory as being stored either in Big-
Endian or Little-Endian format.
这句话会是我们更加迷茫,那如何来使用了。我找了一个帖子博主给出了一个解释,文章来自:
http://www.icdev.com.cn/?1833/viewspace-2112.html
反正先不管大端小端,不用汇编基本没什么区别.只要在端口配置的时候注意一下就可以编程时都用大端访问就没事了.
这是其中的一个解释,另外我们需要知道的是,nboot的开发环境是ADS1.2或者vs2005,这两个环境下关于arm的编译器ADS是armasm,vs2005的实际上也是调用的armasm.exe,具体文章请参考:
http://www.cnblogs.com/huaping-audio/archive/2009/03/18/1415893.html
这里需要点下题目了,因为我们在ADS开发的时候会做一个选择芯片类型的动作,2440是ARM920T,而ADS需要对其进行修改,同时,默认的字节顺序是小端,所以我们这里设置成一个小端的模式。也只在为了汇编部分的开发方便,在下面我们还会提及到一次这个问题。到遇到了我们再细说。这里第一个部分我们就说的差不多了。进入下一个部分
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//第二部分:2440初始化部分
244x_init.s
Memcfg.inc
这个地方是非常重要的部分,上面准备文章中有对2410_init.s文件进行简单的描述,这里2440和2410的功能是完全相同,所以我们稍微更换一个主语:
244x_init.s是汇编程序,所作的工作有:屏蔽所有中断、设置CPU的速度和时钟频率、RAM的初始化、LED的初始化等。
这里需要读者有一定的汇编知识,在附加资料中的other文件夹中我附上了一个arm指令集的pdf文档,ARM指令(宛城布衣).pdf,这个是公认比较全面描述arm汇编指令集的资料,有需要的可以仔细阅读。
下面分析一下244x_init.s的执行流程,对程序里面细节的部分我不做过多的描述,这里对程序的流程进行梳理,操作上大同小异。
进入244x_init.s首先引用了两个汇编的头文件,一个是地址初始化的头文件,这个文件在上面我们已经介绍了,接着是memcfg.inc,这个文件对内存设置进行了定义,这里我们用的是64MB的SDRAM。接下来定义的是将$HandleLabel地址空间中的数据给PC,中断服务程序的入口并导入要用到的字符常量。这些都是常规的一些操作,完成后我们将进入本文件的主要入口点,首先需要做的是关闭中断和看门口,接着是设置时钟频率,这个地方大家需要阅读一下samsung2440手册的第7章,关于时钟和电源管理这个部分的内容,因为在这里我们要对ARM的一些基本功能进行设定,所以,程序上的顺序是首先完成时钟初始化工作,产生时钟后,电源管理部分才可以正常工作,然后进入电源管理部分,对电源的一些属性进行初始化工作。这里对电源管理部分的初始化中,大家要注意到芯片有几种状态,普通状态,等待状态,低功耗状态和休眠状态,对于这几种状态的控制上需要结合时钟来设定,这也就是为什么时钟和电源部分需要同时来完成初始化。另外要格外注意的是休眠状态,因为一般情况下机器都要做一个休眠的功能,而此状态的实现从这个阶段开始一直到ISR以及IST阶段都是紧密联系的,一个环节有问题都可能导致无法休眠唤醒。关于休眠唤醒到说到ISR和IST中断的时候在详细来看。在手册上249页有详细描述休眠唤醒的流程。
接下来完成了时钟和电源的初始化,将需要对内存SDRAM,Flash进行一个初始化和片选的工作。这里包括初始化各种模式下的堆指针,以及将数据段拷贝入SDRAM当中,并准备跳入C语言的main入口,完成bootloader的初始化工作。
到这里对2440的初始化即将告一段落,跳入main入口后将进入另外一个阶段,这里我们看到main有一种特别的亲切感,用过51单片机的朋友一定对这个入口不会陌生,我们在回头思考下,51的初始化也不是差不多这样的一个流程?刚刚还觉得非常难以理解的arm其实他的流程与51还是有相同之处,这里又带出了一个话,嵌入式系统的通性。进入main后就是一个无穷无尽的死循环,直到断电,或者如果有无限的电源,将会循环到世界的末日。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////第三部分:2440其他一些外设的初始化
244X_lib.c
244X_lib.h
Def.h
Option.h
这个部分很好理解,而且是我们熟悉的C语言写的,所以读起来非常快,也好懂,这里主要是对2440的一些外设进行初始化,比如说GPIO口,串口进行初始化,同时在这里需要提到的是,串口的初始化是很重要,因为这是唯一让我们能知道当前系统是否正常运行一个可见的条件,当然可以通过测量始终来判断,但是通过串口如果能看到一些打印信息,咱们就基本上可以宣布boot成功了。所以这个地方大家可以仔细看看uart的处理部分。说起来也很简单一共也就5个函数,初始化,接受和发送,发送包括发送字节和字符串,这里就不对程序进行仔细分析了,c语言的。比刚才看汇编的亲切多了。
在这里有一个很重要的问题,mmu,在Option.h里面定义了关于MMU_EnableICache和MMU_EnableDCache两个函数,这两个函数主要功能是使能数据和指令cache,这里找了一个代码分析的文章:
http://blog.csdn.net/garby2004/archive/2009/09/28/4605048.aspx
void MMU_EnableDCache(void)当地址Cache数据Cache分开时,使能数据Cache;当地址Cache数据Cache统一时,使能整个Cache。
这里再看一个帖子:
http://blog.csdn.net/gooogleman/archive/2009/01/05/3705173.aspx
cache:一个和CPU很近的高速存储器,用来存储一些不是经常变化的数据,提高速度。在经常改变的数据的时候不适合启用,否则效率会更低
比如我们访问GPIO等不能使用cached 地址,就是这个原因,经常替换,效率很低的。(这个东西,也是我们PC的CPU的重要指标)
MMU:用在多任务操作系统中,给每个任务提供独立的虚拟地址空间,其实现原理是:在主存中存贮页表等数据,通过MMU映射到CPU,然后CPU就可以使用虚拟地址调度任务,访问外设等,虚拟地址和物理地址映射是固定的,这样操作系统比较安全稳定。
在bootloadr中的mmu是使得arm以及cache的使用效率更高。而在oal层的mmu上,是真正的处理地址与映射表之间的关系。并不冲突。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//第四部分:对nandflash的初始化
nand.c
Nand.h
nand_s.s
为啥叫nboot呢,写全了就是nandflash boot,从nandflash启动,这里当然要对nand好好的来一番设定和配置。这里一共包含三个文件,nand_s.s,nand.c和nand.h。这里还是要回到手册第六章,关于nand的操作上,基本的流程为,初始化,完成后分析坏块,完成后读取nandflash内容。在这里mini2440多做了一手也就是多了个分析flash大小的功能。具体的功能实现大家可以自己阅读代码连通手册一起分析。这里提一下ECC校验的事情,这个篇文章也是被转摘了无数次,大家可以阅读下了解下ECC校验
http://bluefish.blog.51cto.com/214870/60695
在samsung的手册219页对ECC进行了特别的介绍。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//第五部分:NBOOT.c
这是全文的最后一个部分,也是nboot的终结之处。因为友善新做了一个开机logo动态进度条的功能,nboot.c第一眼看上去很复杂,其实和以往的是一样,最关键的还是在ReadImageFromNand函数中。在《Nboot程序详细分析》一文中的2410loader.c就是我们这里的nboot.c。所以大家可以直接阅读此文对nboot和2410loader.c进行一个比较。其他一些功能函数比如图片加载和动态条大家可以学习一下,在项目开发中可以用到。
到这里整个nboot的程序结构我们都梳理了一遍。至于怎么生成一个nboot.bin或者nb0,如果你用ADS的话会直接生成一个bin文件,而用vs2005,大家就可以参考《S3C2410&&WINCE6.0&&NBOOT》这篇文章中介绍的编译方式。
nboot开发部分学习笔记结束