用以太网Boot启动WinCE的完整过程浅析

2010-8-8

 

1、为什么需要Nboot

S3C2410处理器支持将启动代码存储在NAND Flash中。为了实现这一功能,2410配备了一个名为“Steppingstone”的内部SRAM。在启动时,NAND Flash中第一个4K字节的内容将被加载到Steppingstone中并执行。这个工作由MCU主动完成,而我们只需将NAND Flash配置为Auto Boot模式即可。

       一般来说,启动代码会拷贝存储在NAND Flash中的内容至SDRAM中。在使用ECC校验时,NAND Flash中数据的有效性将被确认。在完成拷贝的工作后,启动代码将跳转到已加载到SDRAM中的主程序中,这时启动代码的使命完成,MCU由主程序来控制。

       WinCE操作系统从文件的组成来看一般分为两部分:BOOTLOADERNK.bin。在WinCE中,BOOTLOADER一般为EBOOT。它的主要功能是初始化硬件设备,主要包括CPU内部的相关控制器、内存、网络、串口甚至USB口和LCD。在初始化完成后,它将通过网络或USB从外部下载NK.bin,或从本地Flash中加载NK.bin并执行,从而启动WinCE操作系统。可以看到Eboot虽然是启动代码,但它得完成相当多的工作,最终的映像文件也将超过4K。所以,我们不能直接将Eboot存放在NAND Flash的第一个4K字节中。我们需要一个更小的启动代码,这就是通常所说的NBOOT(NAND BOOT)

 

2、Nboot必须完成的工作

1.       初始化CPU内部相关控制器,如设置GPIO,关闭Watch Dog,关闭中断,设置系统时钟。

2.       初始化内存。

3.       初始化串口,主要用来输出调试信息。

4.       初始化NAND Flash,因为在MCU启动时默认是Auto Boot模式,为了从NAND Flash中读取EBOOT,需要将其配置成 NAND Flash Mode。将代码和数据拷贝到SDRAM运行

5.       读取NAND Flash中的EBOOT映像文件,并放在内存指定的位置,这个地址是跟EBOOT有关,介绍EBOOT时再详细说明。

6.       完成读取之后,跳转到EBOOT的起始位置,执行EBOOT代码。

 

3、Nboot的注意事项

1、ADS编译Nboot时,注意RO_BASE必须设置为0x0RW_BASE可以不设

2、Nboot要控制在4K以内

3、Nboot最后有个Launch(JumpAddr);这个Launch函数是nboot2440slib.s中定义的,功能是将JumpAddr赋给PC完成跳转,根据JumpAddr地址来决定是跳到Eboot还是跳到NK内核中。JumpAddr地址的定义在2440loader.c

这里在smdk2440\inc\Loader.h中有约定将Nboot烧入到Nandflash的第0块,将TOC烧入第1块,将Eboot烧入第2块中

4Eboot中的动作

我们可以从3中看到Nboot是如何跳转到Eboot中的,下面看Eboot文件下的东西

 

5Eboot的流程

       1ebootnk公用一段起始代码fw.s,所以我们会在eboot文件夹下的arm子文件夹找到fw.s,里面就一句话:     INCLUDE ..\\..\\kernel\\hal\\arm\\fw.s,对于这段起始代码我就不详细分析,无非是建立好中断向量表,设置好系统的工作频率,设置MMU等,然后就跳转到ebootmain函数。

       2ebootmain函数在eboot文件夹的main.c里面,代码如下:

       3BootloaderMain函数,这个就是eboot真正的main函数,这个函数是微软的ceeboot的通用函数,它会调用在eboot文件夹里面由OEM商或者自己写的一些函数。

6BootloaderMain函数的主要动作。

       1BootloaderMain 函数里面首先执行KernelRelocate,这是把一些全局变量存放到ram里面去,这个函数不是很重要。

    2下面就是执行OEMDebugInit,看到OEM三个字母了没有,这就说明这个函数是OEM商,或者我们自己需要实现的,在eboot下的main函数里面可以找到这个函数,这主要是提供给blcommon一些回调函数如下所示:

BOOL OEMDebugInit()

{

     // Assign callback functions to be usec by blcommon.

     g_pOEMReportError     = OEMReportError;//错误报告函数

     g_pOEMVerifyMemory    = OEMVerifyMemory;// 下载映象时检测内存是否正常

     g_pOEMMultiBINNotify = OEMMultiBINNotify;    //通知需要下载的所有bin文件

     OEMInitDebugSerial();//初始化串口调试输出

     return TRUE;

}

这些被调用的函数也是OEM商或者我们自己编写的。前面三个函数都可以在main.c里面找到,代码比较罗唆,而且基本上和硬件没有太大关系,我们看看最后一个初始化串口调试输出的函数,这个文件在D:\WINCE420\PLATFORM\smdk2410eboot+rtc\KERNEL\HAL\debug.c里面,我这里是设置串口0为调试输出口,三星自带的用的是串口1,并且把波特率设置为115200,大家如果需要用串口0作为调试输出口可以参考我的修改:

#define      UART0BaudRate       115200

void OEMInitDebugSerial(void)

{

     volatile UART1reg    *s2410UART0     = (UART0reg *)UART0_BASE;

     volatile IOPreg      *s2410IOP    = (IOPreg *)IOP_BASE;   

        s2410IOP->rGPHCON &= ~((3 << 8) | (3 << 10));   

        s2410IOP->rGPHCON |=   ((2 << 4) | (2 << 6));        //

        s2410IOP->rGPHUP   |=    (1 << 2) | (1 << 3);              

        s2410UART0->rUFCON   = 0x0;         // Disable the FIFO

        s2410UART0->rUMCON   = 0x0;               // Disable AFC.

        s2410UART0->rULCON   = 0x3;         // Normal mode, N81.

        s2410UART0->rUCON    = 0x245;    

        s2410UART0->rUBRDIV = ( (int)(S2410PCLK/16.0/UART0BaudRate + 0.5) -1 );  

}

调用完这个调试输出初始化函数以后,eboot的调试信息就会从串口0出来(当然nk的调试信息也会从这个串口出来了,因为这一部分是和nk复用的。

    3OEMPlatformInit,这个函数也在ebootmain.c里面可以找到,主要是初始化硬件平台,包括设置RTC时钟,初始化USB(InitUSB)、初始化中断Isr_Init初始化一下NANDflash(BP_init),采用微软的BootPart模块提供对Flash设备的分区功能和对BinFS的支持,BP_initG:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\ETHDBG\BOOTPART\bootpart.cpp中定义。然后就是读TOC (table of contents),一般TOC都会烧到nandblock1里面,如果读TOC失败,就会用默认的参数重写TOC,读TOC这段代码比较简单,在fmd.cpp里面。然后就是进入倒计时,如果在设置的延迟时间内按键盘的话就会进入BootMonitor这个函数,这个函数主要是输出eboot的选择菜单,根据你的选择进行操作,如果在延迟时间结束你没有按键盘的话就会根据你设置的是Download new(下载新的映象)还是Launch existing(加载在nand中的映象)来进行下一步操作。

(1)BootMonitor函数,这个函数虽然代码很多,但是其实非常简单,就是根据你的输入来设置改变一些全局变量,eboot在后面会根据这些变量来进行相应的操作。

(2)如果选择了下载映象,在OEMPlatformInit函数里会调用InitEthDevice初始化网卡,然后返回trueInitEthDevice函数在ether.c里面,具体需要根据你使用的网卡,把一些接口提供给eboot

 

(3)、如果我们选择了Launch existing image,在ebootOEMPlatformInit里就会利用ReadRamImageFromBootMedia或者ReadKernelRegionFromBootMedia函数把nknand中读到ram里面,然后再启动内核。第一个函数是直接把内核从nand中拷贝到RAM里面,第二个函数必须要选择了支持binfs文件格式,它会把nand进行格式化成binfs,这些对nand操作的函数都再fmd.cpp里面,具体实现可以参考里面的代码。

4BootloaderMain下面就调用OEMPreDownload进行一些下载前的准备工作,之后就会调用DownloadImage下载内核,下载完了后就调用OEMLaunch启动RAM里面的内核,注意OEMLaunch里面会需要和PB建立连接,如果我们要绕过PB下载nk,我们就需要屏蔽这段代码(在#ifndef SIMULATOR #endif之间)。

 

posted on 2010-08-11 17:25  jiege  阅读(800)  评论(0编辑  收藏  举报