WINCE6.0+S3C2443的启动过程---eboot

WINCE6.0+S3C2443的启动过程---eboot1

 

我们知道从nboot把eboot从nandflash中拷贝到内存指定的地址后,就接着在这个地址处开始运行eboot了,之后,nboot的工作就完成了,那么那么eboot开始执行的地址在哪里呢?我们看看/Src/Bootloader/Eboot/boot.bib下面的配置

 

MEMORY

;   Name     Start     Size      Type

;   -------  --------  --------  ----

    ARGS     80020800  00000800  RESERVED

    RAM      80021000  0000B000  RAM    

    STACK    8002c000  0000A000  RESERVED

    EBOOT    80038000  00040000  RAMIMAGE

BINFS    80080000  00021000  RESERVED

我们根据EBOOT的这一项可以知道,EBOOT对应的虚拟起始地址就是0x80038000,实际的物理地址是0x30038000,根据/Src/Bootloader/Eboot/sources下面的内容

TARGETNAME=eboot

TARGETTYPE=PROGRAM

RELEASETYPE=PLATFORM

EXEENTRY=StartUp

可知eboot的入口是StartUp,下面两个图是从eboot.map的截取出来的

WINCE6.0+S3C2443的启动过程---eboot1 - 男儿当自强 - 男儿当自强的博客

通过上图可以知道eboot的入口地址是0x00009d68

WINCE6.0+S3C2443的启动过程---eboot1 - 男儿当自强 - 男儿当自强的博客

根据上图可知StartUp函数的地址是0x00009d68,所以可以确定eboot的入口地址就是Startup函数,也就是eboot从这个Startup函数开始执行。

 

1.startup函数

系统上电后第一步就是运行Startup函数的代码,这是一个汇编语言函数,主要其最主要功能是执行芯片级初始化:禁止中断,配置系统时钟频率,复制BootLoader镜像到内存,设置存储器的读写周期,构造内存映射表,启用MMU,并启用虚拟内存等操作。

 

Startup函数有两条重要的地址定义,定义ram空间的物理基地址和页表的基地址,这是startup函数主要操作的物理地址空间,如下所示

 

定义RAM空间的物理基地址和页表的基地址

PHYBASE EQU 0x30000000 ; physical start

PTs EQU 0x30010000 ; 1st level page table address (PHYBASE + 0x10000)

; save room for interrupt vectors.

 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xxxluozhen/archive/2010/08/03/5783705.aspx

⑴startup函数的入口

入口函数首先通过对协处理器的操作来清空TLB、指令Cache和数据Cache

p15是系统控制协处理器,主要是对内存还有cashe进行管理。mcr指令,把ARM寄存器中的值传递到协处理寄存器中。C8 是TLB Control 寄存器,C7是Cache/Write Buf Control 寄存器,

ResetHandler

    ; Make sure that TLB & cache are consistent

    mov     r0, #0

    mcr     p15, 0, r0, c8, c7, 0           ; flush both TLB

    mcr     p15, 0, r0, c7, c5, 0           ; invalidate instruction cache

mcr     p15, 0, r0, c7, c6, 0           ; invalidate data cache

下面为了更好去理解上面这段代码,我们来学习相关知识:

①MCR和MRC

对CP15协处理器的操作使用mcr和mrc两条协处理器指令,这两条指令的记法是从后往前看:mcr是把r(CPU核寄存器)中的数据传送到c(协处理器寄存器)中,mrc则是把c(协处理器寄存器)中的数据传送到r(CPU核寄存器)中。对CP15协处理器的所有操作都是通过CPU核寄存器和CP15寄存器之间交换数据来完成的。

 

②TLB

TLB(translation lookaside buffer),旁路转换缓冲区,或称页表缓冲,里面存放的是一些页表文件(虚拟地址到物理地址的转换表),TLB是MMU中的一块高速缓存(也是一种cache),它缓存最近查找过的V对应的页表项,如果TLB里缓存了当前VA的页表项就不必做Translation Table Walk(也就是从发出VA到定位到PA的过程)了,否则去物理内存中读出页表项来保存在TLB中,TLB缓存可以减少访问物理内存的次数。

WINCE6.0+S3C2443的启动过程---eboot1 - 男儿当自强 - 男儿当自强的博客

 

③instruction cache

instruction cache(ICache),cache是高速缓冲存储器,是介于CPU和主存之间的缓冲器,ICache是用于存在正在执行的指令地址附近的一部分指令,供CPU在一段时间内使用。

当系统上电或重起(Reset)的时候,ICaches功能是被关闭的,我们必须往lcr bit置1去开启它,lcr bit在CP15协处理器中控制寄存器1的第12位(关闭ICaches功能则是往该位置0)。ICaches功能一般是在MMU开启之后被使用的(为了降低MMU查表带来的开销),但有一点需要注意,并不是说MMU被开启了ICaches才会被开启,正如本段刚开始讲的,ICaches的开启与关闭是由lcr bit所决定的,无论MMU是否被开启,只要lcr bit被置1了,ICaches就会发挥它的作用,见下图

WINCE6.0+S3C2443的启动过程---eboot1 - 男儿当自强 - 男儿当自强的博客

 

④data cache

data cache(DCache),cache是高速缓冲存储器,是介于CPU和主存之间的缓冲器,DCache是用于存在正在执行的指令地址附近的一部分数据,供CPU在一段时间内使用。

WINCE6.0+S3C2443的启动过程---eboot1 - 男儿当自强 - 男儿当自强的博客

 

 

ARM920T有16KB的ICache,也有16KB的DCache,另外外加4KB的steppingstone,那么S3C2440自带的RAM有36KB.

 

与ICaches一样,系统上电或重起(Reset)的时候,DCaches功能是被关闭的,我们必须往Ccr bit置1去开启它,Ccr bit在CP15协处理器中控制寄存器1的第2位(关闭DCaches功能则是往该位置0)。与ICaches不同,DCaches功能是必须在MMU开启之后才能被使用的。

WINCE6.0+S3C2443的启动过程---eboot1 - 男儿当自强 - 男儿当自强的博客


Eboot是通过下面的操作来disable ICache和DCache的

mcr     p15, 0, r0, c7, c5, 0           ; invalidate instruction cache

mcr     p15, 0, r0, c7, c6, 0           ; invalidate data cache

 

c7是个只写寄存器,这个寄存器用来管理ICache和DCache,其中包括Invalidate cache

见下图我们就知道上面代码的意义了。

 

 

 

WINCE6.0+S3C2443的启动过程---eboot1 - 男儿当自强 - 男儿当自强的博客

 

--->后面待续

 

S3C2443时钟管理  

S3C2443有两个PLL用来产生内部时钟,分别是MPLL和EPLL,其中MPLL为包括ARM,AHB和APB的总体功能模块产生内部时钟,而EPLL为比如是USB,I2S和camera等这些具体的模块产生时钟,我们可以通过软件编程来控制这个两个PLL的工作频率,可以关闭和开启内部时钟源来减少功耗。

 

1.MPLL和EPLL时钟源的选择

从上图可知主要的时钟源来之外部晶振(XTI)或者外部时钟(EXTCLK),时钟产生器由MPLL和EPLL组成,这两个PLL的作用是可以产生S3C2443所需要的高频时钟信号。由OM[0]来决定MPLL是选择XTI还是EXTCLK来作为时钟源,而OM[0]是由硬件设计来确定,下图是我们项目OM[0]的设计部分:

在此设计中,OM[0]=1,根据下表

可知MPLL的时钟源是由XTI提供,如下图所示:

 

由上面左图可知EXTCLK是通过0R的电阻直接接地的,所以EPLL只能选择XTI来作为EPLL的时钟源的,再根据下图:

我们可知,CLKSRC[8]=0,CLKSRC[7]=X,这里X可以是0或者1,这是需要在startup.s中做相应的设置的。

 

 

2.PLL(phase-locked-loop)

S3C2443的PLL主要由PFD(phase difference detector,相位差检测器)、charge pump(电荷泵)、VCO(voltage controlled oscillator压控振荡器)和off-chip loop filter(外部环路滤波器)。

 

PFD:又称为相比比较器,它的作用是检测输入信号和输出信号的相位差,并将检测出的相位差信号转换为电压信号输出。

 

Charge pump:电荷泵转变PFD的电压输出信号成一定比例的电压值发送给VCOoff-chip loop filter

 

Off-chip loop filterPFD输出的电压信号,进入charge pump后,可能会有高频杂波,通过Off-chip loop filter 可以输出VCO需要一个稳定的电压,在这里,Off-chip loop filter采用典型的RC低通滤波。

 

VCO:输出电压进入VCO,引起振荡器频率的变化,压控振荡器的输出频率随其输入电压的改变而改变,当FrefFvco没有差别的时候,电压就会保持稳定下来,PFD就停止输出电压信号给charge pump,这样PLL系统时钟就稳定了。

 

 

3.改变PLL设置

S3C2443在平常的工作模式中,我们可以通过来写PMS的值来改变PLL的输出频率,当我们通过软件来写PMS的值时,PLL的锁存(lock time)被自动插入,在这个lock time期间,PLL是没有产生有效的时间给S3C2443的,在lock time过后,PLL才产生有效和稳定的clock给SYSCLK,见下图。

PMS分别指的是PDIV、MDIV和SDIV,而PDIV是值PLL main divider value,MDIV是指PLL pre-divider value,SDIV是指PLL post-divider value,控制MPLL和EPLL时钟的寄存器MPLLCON和EPLLCON否有这几个值的定义。

 

4.系统时钟控制

由下图可知ARMCLK是ARM920T的内核时钟,也是S3C2443的CPU时钟;HCLK是内部AHB bus和比如是内存控制器、中断控制器、LCD控制器等外围设备的基准时钟;PCLK是内部APB bus和比如是WDT、IIS、I2C等外围设备的基准时钟;DDRCLK是MDDR内存的data strobe时钟。

4.1 MPLL的时钟控制

从上图可知,MSysClk是ARMCLK、HCLK、PCLK、DDRCLK这些时钟的基准时钟,而ARMCLK、HCLK、PCLK、DDRCLK这些时钟到底有什么关系呢,通过对CLKDIVO控制寄存器的设置可以得到它们之间不同的比值关系,见下表

 

4.2 EPLL的时钟控制

从上图可知EPLL的时钟ESYSCLK被用作不同的外围控制器提供基准时钟,通过divider的分频可以得到不同外围控制所需要的时钟,而这个分频值是通过对CLKDIV1寄存器的配置来实现的,也可以通过编程SCLKCON寄存器来关闭或者开启不同外围控制器的时钟。

 

在stop和sleep模式,EPLL将被自动关闭,在退出stop和sleep模式的时候,如果SCLKCON寄存器中相关位被使能的情况下,那么EPLL将为使能的外围控制器产生时钟。

 

5. 上电复位PLL时钟的启动流

在电压源提供所需要的电压给系统上电复位后,晶体振荡器在几毫秒之内起振,刚开始的时候MPLL和EPLL都是停止的。当nRESET在晶振时钟稳定后释放(由低电平变为高电平),PLL开始是使用PLL的输入时钟Fin作为SYSCLK时钟的,系统上电复位后,必须通过软件来配置MPLLCON和EPLLCON使用每个PLL,也即通过写MPLLCON和EPLLCON的PDIV、MDIV和SDIV值,接着会自动插入PLL的lock time,lock time之后,PLL的输出时钟Fout就是作为SYSCLK时钟来使用了,这些动作一般是在startup.s函数中初始化的,见下图

 

2 main函数

void main(void)

{

    //MemoryTest_Function();

    BootloaderMain();

    // Should never get here.

    SpinForever();

}

Main函数主要是通过调用BootloaderMain函数来实现其功能的,下面来看看BootloaderMain函数的流程图:

                                         

2.1 KernelRelocate()

 

⑴pTOC的结构体ROMHDR

结构体ROMHDR在/WINCE600/PUBLIC/COMMON/OAK/INC/Romldr.h中定义,如下所示

 

 

 

从上图我们知道Physical first=0x80038000,这就是eboot/boot.bib中eboot指定的地址

EBOOT    80038000  00040000  RAMIMAGE

Physical last=0x8004FE54=image start+length=0x80038000+0x00017E54,所以从physical first到physical last这段内存的大小就是eboot.bin的大小

 

RAM Free – RAM Start=0x7000,这段RAM用于做什么呢?不知道,还望知者指教,难道是用于全局变量的重定位吗?用于把boot loader中的全局变量重定位到这段RAM中吗?我想也许是,见我发的相关帖子http://topic.csdn.net/u/20101009/10/d2598ab6-f926-49f1-a708-7bc8c9ec2e6d.html

对于如何实现重定位的,见下面这个链接,在此就不描述了。

http://blog.csdn.net/chinesedragon2010/archive/2010/10/09/5929007.aspx

 

2.2 OEMDebugInit ()

BOOL OEMDebugInit(void)

{

 

    // Set up function callbacks used by blcommon.

    //

    g_pOEMVerifyMemory   = OEMVerifyMemory;      // Verify RAM.

    g_pOEMMultiBINNotify = OEMMultiBINNotify;

 

    // Call serial initialization routine (shared with the OAL).

    //

    OEMInitDebugSerial();

 

    return(TRUE);

}

OEMDebugInit函数主要用于设置后blcommon.lib库需要回调的函数OEMVerifyMemory和OEMMultiBINNotify,这两个函数的具体作用,后面再详细描述。OEMDebugInit函数还调用OEMInitDebugSerial函数来初始化用于debug的串口端口。

 

2.3 OEMPlatformInit ()

注:本文是基于SD卡的更新方式

OEMPlatformInit()的工作如下:

2.3.1 初始化显示控制器

通过调用函数InitDisplay来初始化LCD控制器,初始化之后可以来显示eboot阶段的logo信息。

 

2.3.2 初始化BSP参数结构体

通过调用函数OALArgsInit(pBSPArgs)来初始化BSP的共享数据,OAL与EBoot会共享一些参数,即EBoot会将一些参数传给OAL使用,在此可以给参数初始化。

// Initialize the BSP args structure.

    //

OALArgsInit(pBSPArgs);     

pBSPArgs在eboot/loader.h的相关定义如下

// Driver globals pointer (parameter sharing memory used by bootloader and OS).

//

#define pBSPArgs        ((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START)

IMAGE_SHARE_ARGS_UA_START对应的虚拟和物理地址的宏定义如下:

#define IMAGE_SHARE_ARGS_PA_START       0x30020000

#define IMAGE_SHARE_ARGS_UA_START       0xA0020000

pBSPArgs是一个结构体((BSP_ARGS)类型的指针。BSP_ARGS结构体的成员中,就保存了这些共享参数。它指向的是bootloader和OS共享的参数内存区域,用于在bootloader和OS的OAL及驱动之间传共享的参数,这个内存的其实地址和大小在files/config.bib下面定义:

; Common RAM areas

       ARGS                80020000  00000800  RESERVED

 

接下来看看BSP_ARGS结构体的定义:

typedef struct {

    OAL_ARGS_HEADER header;

    UINT8 deviceId[16];         // Device identification

    OAL_KITL_ARGS kitl;

    //UINT8 uuid[16];

    BOOL bUpdateMode;      // TRUE = Enter update mode on reboot.

    BOOL bHiveCleanFlag;     / TRUE = Clean hive at boot

    BOOL bCleanBootFlag;     // TRUE = Clear RAM, hive, user store at boot

    BOOL bFormatPartFlag;     // TRUE = Format partion when mounted at boot

       DWORD      nfsblk;

       HANDLE g_SDCardDetectEvent; //kim

       DWORD g_SDCardState ;

       //我们可以在这个结构体中定义项目所需要的在bootloader和OS之间共享的数据。

} BSP_ARGS, *PBSP_ARGS;

重点解释下面的结构体成员:

header是信息头,用来指示pBSPArgs所指内存是否包含有效信息。

deviceId是设备ID,用来标识KITL使用的端口外设。

kitl用于存储KITL端口的相关配置信息。

 

2.3.3 初始化nandflash及从nandflash中获取信息

⑴FMD_GetInfo()

// Get flash info

    if (!FMD_GetInfo(&flashInfo)) {

        OALMSG(OAL_ERROR, (L"ERROR: BLFlashDownload: "

            L"FMD_GetInfo call failed/r/n"

        ));

}

FMD_GetInfo的主要函数体如下:

 

先是通过ReadFlashID函数来得到当前nandflash的ID,然后分离出此ID的MID和DID,接着通过数值astNandSpec来比较当前nandflash的MID和DID是否和astNandSpec中支持的吻合,如果不吻合就需要在astNandSpec中假如,这也是如果项目所使用的nandflash发生变化时,而astNandSpec又没有相应的支持,就需要astNandSpec中假如新的nandflash的技术参数。

 

 

获取nandflash的技术参数,比如此nandflash有多少个block,每个block有多少页,每个sector的大小是多少,每个block有多少个Byte。

 

 

2.3.4 读取TOC信息

TOC:Table Of Contents, OEM on disk structure.

通过调用函数TOC_Read()来从nandflash中读取出TOC的信息

 

我们目前nandflash的保存布局是:stepldr保存在第0个block中,TOC保存在第1个block中,eboot保存在第2个block中,nk保存在第三个block开始的地方,上面的代码是从第1个block中把TOC的信息读取出来保存在g_pTOC这个全局的指针数组中。

 

通过判读从nandflash中读取出来的g_pTOC是否为NULL和g_pTOC->dwSignature是否等于0x434F544E来判断当前的TOC信息是否有效。

 

Si是SectorInfo的结构体变量,这个结构体的定义如下:

typedef struct _SectorInfo

{

    DWORD dwReserved1;              // Reserved - used by FAL

    BYTE  bOEMReserved;             // For use by OEM

    BYTE  bBadBlock;             // Indicates if block is BAD

    WORD  wReserved2;               // Reserved - used by FAL

   

}SectorInfo, *PSectorInfo;

在NAND FLASH中,每个物理扇区的Spare区都保存一个SectorInfo的数据结构:

dwReserved1:这部分保留给FAL层使用,FAL层将填写逻辑扇区号。

bOEMReserved:这部分保留给OEM使用,可用于定义读写属性。

bBadBlock:这部分是由nandflash芯片坏块标志定义。

wReserved2:这部分保留给FAL层使用,FAL层将填写标志位来防止掉电错粗。

FAL层通过FMD_ReadSector与FMD_WriteSector函数来获取和写入扇区信息。

 

 

解析来看看TOC的结构体

 

 

 

 

 

 

 

 

 

 

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值