1.1U-Boot工作过程U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:(1)第一阶段的功能硬件设备初始化加载U-Boot第二阶段代码到RAM空间设置好栈跳转到第二阶段代码入口(2)第二阶段的功能初始化本阶段使用的硬件设备检测系统内存映射将内核从Flash读取到RAM中为内核设置启动参数调用内核1.1.1U-Boot启动第一阶段代码分析第一阶段对应的文件是cpu/arm920t/start.S和board/samsung/mini2440/lowlevel_init.S。U-Boot启动第一阶段流程如下:图2.1U-Boot启动第一阶段流程根据cpu/arm920t/u-boot.lds中指定的连接方式:ENTRY(_start)SECTIONS{.=0x00000000;.=ALIGN(4);.text:{cpu/arm920t/start.o(.text)board/samsung/mini2440/lowlevel_init.o(.text)board/samsung/mini2440/nand_read.o(.text)*(.text)}……}第一个链接的是cpu/arm920t/start.o,因此u-boot.bin的入口代码在cpu/arm920t/start.o中,其源代码在cpu/arm920t/start.S中。下面我们来分析cpu/arm920t/start.S的执行。1.硬件设备初始化(1)设置异常向量cpu/arm920t/start.S开头有如下的代码:.globl_start_start:bstart_code/*复位*/ldrpc,_undefined_instruction/*未定义指令向量*/ldrpc,_software_interrupt/*软件中断向量*/ldrpc,_prefetch_abort/*预取指令异常向量*/ldrpc,_data_abort/*数据操作异常向量*/ldrpc,_not_used/*未使用*/ldrpc,_irq/*irq中断向量*/ldrpc,_fiq/*fiq中断向量*//*中断向量表入口地址*/_undefined_instruction:.wordundefined_instruction_software_interrupt:.wordsoftware_interrupt_prefetch_abort:.wordprefetch_abort_data_abort:.worddata_abort_not_used:.wordnot_used_irq:.wordirq_fiq:.wordfiq.balignl16,0xdeadbeef以上代码设置了ARM异常向量表,各个异常向量介绍如下:表2.1ARM异常向量表地址异常进入模式描述0x00000000复位管理模式复位电平有效时,产生复位异常,程序跳转到复位处理程序处执行0x00000004未定义指令未定义模式遇到不能处理的指令时,产生未定义指令异常0x00000008软件中断管理模式执行SWI指令产生,用于用户模式下的程序调用特权操作指令0x0000000c预存指令中止模式处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常0x00000010数据操作中止模式处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常0x00000014未使用未使用未使用0x00000018IRQIRQ外部中断请求有效,且CPSR中的I位为0时,产生IRQ异常0x0000001cFIQFIQ快速中断请求引脚有效,且CPSR中的F位为0时,产生FIQ异常在cpu/arm920t/start.S中还有这些异常对应的异常处理程序。当一个异常产生时,CPU根据异常号在异常向量表中找到对应的异常向量,然后执行异常向量处的跳转指令,CPU就跳转到对应的异常处理程序执行。其中复位异常向量的指令“bstart_code”决定了U-Boot启动后将自动跳转到标号“start_code”处执行。(2)CPU进入SVC模式start_code:/**setthecputoSVC32mode*/mrsr0,cpsrbicr0,r0,#0x1f/*工作模式位清零*/orrr0,r0,#0xd3/*工作模式位设置为“10011”(管理模式),并将中断禁止位和快中断禁止位置1*/msrcpsr,r0以上代码将CPU的工作模式位设置为管理模式,并将中断禁止位和快中断禁止位置一,从而屏蔽了IRQ和FIQ中断。(3)设置控制寄存器地址#ifdefined(CONFIG_S3C2400)#definepWTCON0x15300000#defineINTMSK0x14400008#defineCLKDIVN0x14800014#else/*s3c2410与s3c2440下面4个寄存器地址相同*/#definepWTCON0x53000000/*WATCHDOG控制寄存器地址*/#defineINTMSK0x4A000008/*INTMSK寄存器地址*/#defineINTSUBMSK0x4A00001C/*INTSUBMSK寄存器地址*/#defineCLKDIVN0x4C000014/*CLKDIVN寄存器地址*/#endif对与s3c2440开发板,以上代码完成了WATCHDOG,INTMSK,INTSUBMSK,CLKDIVN四个寄存器的地址的设置。各个寄存器地址参见参考文献[4]。(4)关闭看门狗ldrr0,=pWTCONmovr1,#0x0strr1,[r0]/*看门狗控制器的最低位为0时,看门狗不输出复位信号*/以上代码向看门狗控制寄存器写入0,关闭看门狗。否则在U-Boot启动过程中,CPU将不断重启。(5)屏蔽中断/**maskallIRQsbysettingallbitsintheINTMR-default*/movr1,#0xffffffff/*某位被置1则对应的中断被屏蔽*/ldrr0,=INTMSKstrr1,[r0]INTMSK是主中断屏蔽寄存器,每一位对应SRCPND(中断源引脚寄存器)中的一位,表明SRCPND相应位代表的中断请求是否被CPU所处理。根据参考文献4,INTMSK寄存器是一个32位的寄存器,每位对应一个中断,向其中写入0xffffffff就将INTMSK寄存器全部位置一,从而屏蔽对应的中断。#ifdefined(CONFIG_S3C2440)ldrr1,=0x7fffldrr0,=INTSUBMSKstrr1,[r0]#endifINTSUBMSK每一位对应SUBSRCPND中的一位,表明SUBSRCPND相应位代表的中断请求是否被CPU所处理。根据参考文献4,INTSUBMSK寄存器是一个32位的寄存器,但是只使用了低15位。向其中写入0x7fff就是将INTSUBMSK寄存器全部有效位(低15位)置一,从而屏蔽对应的中断。(6)设置MPLLCON,UPLLCON,CLKDIVN#ifdefined(CONFIG_S3C2440)#defineMPLLCON0x4C000004#defineUPLLCON0x4C000008ldrr0,=CLKDIVNmovr1,#5strr1,[r0]ldrr0,=MPLLCONldrr1,=0x7F021strr1,[r0]ldrr0,=UPLLCONldrr1,=0x38022strr1,[r0]#else/*FCLK:HCLK:PCLK=1:2:4*//*defaultFCLKis120MHz!*/ldrr0,=CLKDIVNmovr1,#3strr1,[r0]#endifCPU上电几毫秒后,晶振输出稳定,FCLK=Fin(晶振频率),CPU开始执行指令。但实际上,FCLK可以高于Fin,为了提高系统时钟,需要用软件来启用PLL。这就需要设置CLKDIVN,MPLLCON,UPLLCON这3个寄存器。CLKDIVN寄存器用于设置FCLK,HCLK,PCLK三者间的比例,可以根据表2.2来设置。表2.2S3C2440的CLKDIVN寄存器格式CLKDIVN位说明初始值HDIVN[2:1]00:HCLK=FCLK/1.01:HCLK=FCLK/2.10:HCLK=FCLK/4(当CAMDIVN[9]=0时)HCLK=FCLK/8(当CAMDIVN[9]=1时)11:HCLK=FCLK/3(当CAMDIVN[8]=0时)HCLK=FCLK/6(当CAMDIVN[8]=1时)00PDIVN[0]0:PCLK=HCLK/11:PCLK=HCLK/20设置CLKDIVN为5,就将HDIVN设置为二进制的10,由于CAMDIVN[9]没有被改变过,取默认值0,因此HCLK=FCLK/4。PDIVN被设置为1,因此PCLK=HCLK/2。因此分频比FCLK:HCLK:PCLK=1:4:8。MPLLCON寄存器用于设置FCLK与Fin的倍数。MPLLCON的位[19:12]称为MDIV,位[9:4]称为PDIV,位[1:0]称为SDIV。对于S3C2440,FCLK与Fin的关系如下面公式:MPLL(FCLK)=(2×m×Fin)/(p×)其中:m=MDIC+8,p=PDIV+2,s=SDIVMPLLCON与UPLLCON的值可以根据参考文献4中“PLLVALUESELECTIONTABLE”设置。该表部分摘录如下:表2.3推荐PLL值输入频率输出频率MDIVPDIVSDIV12.0000MHz48.00MHz56(0x38)2212.0000MHz405.00MHz127(0x7f)21当mini2440系统主频设置为405MHZ,USB时钟频率设置为48MHZ时,系统可以稳定运行,因此设置MPLLCON与UPLLCON为:MPLLCON=(0x7f12)|(0x024)|(0x01)=0x7f021UPLLCON=(0x3812)|(0x024)|(0x02)=0x38022(7)关闭MMU,cache接着往下看:#ifndefCONFIG_SKIP_LOWLEVEL_INITblcpu_init_crit#endifcpu_init_crit这段代码在U-Boot正常启动时才需要执行,若将U-Boot从RAM中启动则应该注释掉这段代码。下面分析一下cpu_init_crit到底做了什么:320#ifndefCONFIG_SKIP_LOWLEVEL_INIT321cpu_init_crit:322/*323*使数据cache与指令cache无效*/324*/325movr0,#0326mcrp15,0,r0,c7,c7,0/*向c7写入0将使ICache与DCache无效*/327mcrp15,0,r0,c8,c7,0/*向c8写入0将使TLB失效*/328329/*330*disableMMUstuffandcaches331*/332mrcp15,0,r0,c1,c0,0/*读出控制寄存器到r0中*/333bicr0,r0,#0x00002300@clearbits13,9:8(--V---RS)334bicr0,r0,#0x00000087@clearbits7,2:0(B----CAM)335orrr0,r0,#0x00000002@setbit2(A)Align336orrr0,r0,#0x00001000@setbit12(I)I-Cache337mcrp15,0,r0,c1,c0,0/*保存r0到控制寄存器*/338339/*340*beforerelocating,wehavetosetupRAMtiming341*becausememorytimingisboard-dependend,youwill342*findalowlevel_init.Sinyourboarddirectory.343*/344movip,lr345346bllowlevel_in