wince系统下s3c6410的bootloader初接触

来源:互联网 发布:2016中国台湾贸易数据 编辑:程序博客网 时间:2024/06/04 23:29

一、概述

       引导加载程序(bootloader)就是在操作系统内核运行前执行的一段小程序。通过这段小程序,我们可以初始化必要的硬件设备,创建内核需要的一些信息并将这些信息通过相关机制传递给内核,从而将系统的软硬件环境带到一个合适的状态,最终调用操作系统内核,真正起到引导和加载内核的作用。

    DDR系统中,该部分的代码位于IDR400-2_SMDK6410/SRC/BOOTLOADER文件夹下。该文件夹下有五个子文件夹NBL1.LSBNBL2EBOOT.WHIMORYEboot.SDFuserNBL1.IROM_SD,其中Eboot.SDFuserNBL1.IROM_SD一起所生成的引导程序用于烧写,也就是说把NBOOTEBOOT和内核镜像从SD卡中烧写到NAND FLASH(相当于DDR系统的硬盘)中去,以后系统正常使用的时候都是从NAND FLASH中读入引导程序,然后引导程序加载内核到内存开始执行;其中NBL1.LSBNBL2EBOOT.WHIMORY所生成的引导程序,则是系统正常运行时的bootloader,该文档主要介绍的就是这个bootloader

 

二、NBL1.LSB

Bootloader最先被执行的就是这个文件夹下的代码,入口是startup.s。这部分代码应该是在CPU片内ROM里面,无需加载,在系统上电的时候自动运行,然后它初始化一些硬件,再从NAND FLASH第一个块(块号为0)中读取NBOOTSDRAM(即内存)中,即规定了NBOOT大小最大只能是一个块大小,其实NBOOT编译完后生成的镜像只有70k左右。

首先在startup.s汇编代码中设置一些硬件环境,如关中断、关看门狗等等,然后跳到main.c文件中的main函数中。

这里有个重要的地址:

#define LOAD_ADDRESS_PHYSICAL             (0x50000000)

这个地址即SDRAM的起始地址

Main函数中流程:

l         main函数中首先通过NAND_Init();初始化NAND FLASH

l         pBuf = (unsigned char *)LOAD_ADDRESS_PHYSICAL;因为这个时候还没有开启MMU,虚拟地址pBuf也就是物理地址,可以直接赋值而无需转换

l         FLASH中读取相应数据到这个地址处

l         ((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))();最后跳转到这个地址处执行

它的功能:

l         开启指令缓存Icache,设置了一些堆栈,以及设置其它硬件坏境

l         加载NBOOT镜像(保存在NAND FLASH第一个BLOCK中)进入RAM中,并启动

 

三、NBL2

首先被执行的依然是startup.s中汇编代码,然后跳转到main.cmain函数中。Main函数的流程如下:

l         OEMInitDebugSerial();初始化串口,此后就可以使用OEMWriteDebugString输出调试信息了

l         FIL_Init();初始化Flash Interface Layer,按我的理解是驱动NAND FLASH,跟进去看这个函数的代码,只是给一个结构体变量赋值NAND操作的一些函数(如NAND_Read_Retry),

l         ShadowEboot();就是加载EBOOT镜像到SDRAM中特定地址了,这个地址就是:

#define EBOOT_VIRTUAL_BASEADDR   0x80030000

用过这个函数pLowFuncTbl=FIL_GetFuncTbl()获取之前FIL_Init()设置好的那个结构体变量,然后通过pLowFuncTbl->ReadNAND_FLASH中读取EBOOT Image

l         OEMLaunchImage(EBOOT_VIRTUAL_BASEADDR);最后用这个函数跳转到EBOOT执行,因为已经开始了MMU,代码中使用的都是虚拟地址,所以要转换成物理地址进行跳转

NBOOT2的功能:

l         开启MMU和数据缓存Dcache,设置其它硬件坏境

l         This routine will initialize the first-level page table based up the contents of the MemoryMap array(这一步不太理解)

l         加载EBOOT镜像(保存在NAND FLASH第三个BLOCK(块号为2)中,最大大小为512K)进入RAM中,并启动

 

四、EBOOT.WHIMORY

4-1、执行流程

Bootloader最主要的工作都在这部分完成,首先被执行的依然是startup.s汇编代码,除了一些例行的初始化硬件坏境设置外,一个重要的功能是建立了虚拟地址的映射机制。然后依然是跳转到main.c文件中的main函数里。

Main函数调用BootloaderMain();BootloaderMain()的执行流程如下:

l         KernelRelocate:重定位全局变量到RAM

l         OEMDebugInit:初始化调试端口

l         OEMPlatformInit:初始化目标板上的设备

l         OEMPreDownload:下载映像之前

l         DownloadImage:下载映像

l         OEMLaunch:启动映像

EBOOT中,OEMPlatformInit是其中的主体,以上的执行流程在OEMPlatformInit之后就跳到内核执行了,下面描述一下这个函数体的整体流程:

1.       OALArgsInit(pBSPArgs); //初始化BSP_ARGS结构体

2.       BP_Init;// initialize the boot media block driver and BinFS partition

3.       FMD_GetInfo(&flashInfo) //获取FLASH信息

4.       TOC_Read( ) //NAND FLASH TOC分区中读取数据

5.       Boot_Keys_Scan();// 检测用户是否进入烧写模式,如果不是则跳到第8

6.       InitializeUSB() //初始化USB,准备烧写

7.       StateMachine3();//启动烧写,烧写完以后,调用SpinForever()终止

8.       ReadOSImageFromBootMedia();//NAND FLASH中读取内核到指定地址

9.       Launch(0x50101000);//从这个地址处进入内核,os开始运行,bootloader完成使命

 

4-2、其它

bootloader如何存放在NAND FLASH

NAND上首先存放着NBOOT,大小为一个块

然后存放着TOC,大小也为一个块,但是预留了一个块

然后存放着EBOOT,大小为五个块,预留了二个块

然后才存放着内核镜像

BINFS到底是什么?

BINFS就是MSCE做的一种存放系统镜像的一个文件系统,但不知如何实现的

一些结构体

UCHAR           g_TOC[SECTOR_SIZE];

const PTOC      g_pTOC = (PTOC)&g_TOC;

上面变量是定义在main.c文件中的全局变量,它用来存储从NAND FLASH TOC分区中读取出来的数据,然后根据这些数据来决定从哪里加载内核镜像到哪里以及其大小。

typedef struct _TOC
{
         //只用来验证接下去内容的合法
         DWORD     dwSignature;
         //包含image的索引、启动delay时间、ip地址、MAC地址和掩码等
         BOOT_CFG    BootCfg;
          //用来描述ce内核image数组
         IMAGE_DESCRIPTOR    id[MAX_TOC_DESCRIPTORS];
         CHAININFO           chainInfo;
 } TOC, *PTOC;          // 512 字节

其中IMAGE_DESCRIPTOR结构体的定义如下:

typedef struct _IMAGE_DESCRIPTOR
{
         DWORD dwVersion;       //编译时的版本号
         DWORD dwSignature;      //“EBOOT”“CFSH”
         UCHAR ucString[IMAGE_STRING_LEN];    //描述字符串:"eboot.nb0"之类
         DWORD dwImageType;      //image的类型
         DWORD dwTtlSectors;         //image文件用到的NAND的扇区总数
         DWORD dwLoadAddress;     //image加载时的虚拟地址
         DWORD dwJumpAddress;    //image加载完成后的跳转地址
         SG_SECTOR sgList[MAX_SG_SECTORS];    
         //image的段描述,包括起始扇区号和所需扇区数目
         ULONG dwStoreOffset;
} IMAGE_DESCRIPTOR, *PIMAGE_DESCRIPTOR;

 

五、总结

    简而言之,bootloader就是在系统开机的时候运行的一段代码,这段代码用来初始化硬件环境、加载操作系统到内存并转入执行。初始化硬件坏境一般都是由汇编代码(如startup.s)完成,这些代码与硬件高度关联,深入了解和改变这些代码以进行调试和配置都需要参考芯片文档(如datasheet)。而加载镜像到SDRAM,都是由c语言代码实现的,其过程在main函数中都比较明朗,其实质都是通过初始化FLASH,然后由NAND_READ()之类的函数把存在于NAND FLASH上的镜像加载到特定的内存地址,然后跳转到这个地址处转到下一步执行。

原创粉丝点击