u-boot的启动阶段分为两个,第一部分主要为start.S文件,帖子尽可能的分析了每一行代码的意思,查看了很多手册,分析的目的也是为了学习吧,写博客也是想给自己的学习留下点东西,这些东西网上其实很多,但是感觉看别人写的和字自己分析写一遍,差别好大。转载请注明出处,下面进入正题。
第11行:
#include #include #include 一.start_code及CPSR分析 第24行: .globl _start _start: b start_code ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq 这里从_start开始,第一句,b start_code意义是跳转到start_code这部分。我们切过去看。 在第79行: start_code: /* * set the cpu to SVC32 mode */ mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr, r0 这部分是将cpu设置成SVC32模式,我们知道arm有7种工作模式,这里设置为等级最高,一般我们是工作在usr模式。 mrs r0,cpsr bic r0, r0, #0x1f 这句话起始就是对r0的低5位清零。bic指令的意思对 Rn 中的值和 Operand2 值的反码按位进行逻辑“与”运算。 orr r0, r0,#0xd3 这里是设置r0里面的低5位为10011,即svc模式,同时关闭irq和fiq。 msr cpsr,r0 将r0的值写回给cpsr。 这里我们看一下s3c2440的datasheet: 这里给出了CPSR寄存器各个位的定义,我们这里着重关心低八位,0到5位设置工作模式,下面的图里面给出了各个模式对应的位应该设置为何值。5,6,7三位分别对应状态位,fiq和irq,上面给r0赋值0xd3就是11010011,对应进去一目了然。 二.关中断,时钟设置分析 下面第102行: #ifdef CONFIG_S3C24X0 /* turn offthe watchdog */ # if defined(CONFIG_S3C2400) # define pWTCON 0x15300000 # define INTMSK 0x14400008 /*Interrupt-Controller base addresses */ # defineCLKDIVN 0x14800014 /* clock divisor register */ #else # define pWTCON 0x53000000 # define INTMSK 0x4A000008 /*Interrupt-Controller base addresses */ # defineINTSUBMSK 0x4A00001C # defineCLKDIVN 0x4C000014 /* clock divisor register */ # endif 这段的功能是定义看门狗,中断和子中断以及分频器的寄存器地址,此处我们的是s3c2440,可以看看数据手册,以INTMSK为例。· INTMSK的基地址果然是0x4A000008. 下面,第116行: ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] ldr这里使用了伪指令,是将pWTCON的地址写到r0里面。mov讲0赋给r1,最后str是将r1的值放到r0代表的地址的内存里面去。这段话其实就是对pWTCON清零来关闭看门狗。 第123行: mov r1,#0xffffffff ldr r0, =INTMSK str r1, [r0] 参考上一段话,因为中断控制寄存器都是置一清零的,这里是关闭所有的中断。 第133行: #if defined(CONFIG_S3C2440) ldr r1, =0x7fff ldr r0, =INTSUBMSK str r1, [r0] #endif 这部分是屏蔽子中断,2440的子中断控制寄存器只有低15位有效,别的位保留,所以这里为0x7fff。 第139行: #if defined(CONFIG_S3C2440) #define MPLLCON 0x4c000004 #define UPLLCON 0x4c000008 #define CAMDIVN 0x4c000018 ldrr0,=CAMDIVN mov r1,#0 str r1,[r0] ldrr0,=CLKDIVN movr1,#0x05 str r1,[r0] mrcp15,0,r0,c1,c0,0 orrr1,r1,#0xc0000000 mcrp15,0,r0,c1,c0,0 ldrr0,=UPLLCON ldrr1,=0x38022 str r1,[r0] nop nop nop nop nop nop nop ldrr0,=MPLLCON ldrr1,=0x5c011 str r1,[r0] #else 上面这段主要做了三个时钟的设置,第一个关闭了为摄像头的分频器,第二个设置USB的时钟频率为48M,第三设置系统的时钟频率为400MHZ.具体的为什么,我们来看看。 CLKDIVN寄存器参看数据手册如下: mov r1,#0x05也就是0101,由于我们设置了CAMDIV均为0,因此对应的PCLK:HCLK:FCLK=1:2:8,分频系数已经设置好。 mrc p15,0,r0,c1,c0,0 orr r1,r1,#0xc0000000 mcr p15,0,r0,c1,c0,0 此处为将协处理器p15的寄存器中的数据传送到ARM处理器的寄存器r0中,其中1是协处理器操作码1,0是协处理器操作码2,c1存放第一个操作数的协处理器寄存器,c0存放第二个操作数的协处理器寄存器。最终目的是将arm从快速总线模式转换为异步总线模式。 ldr r0,=UPLLCON ldr r1,=0x38022 str r1,[r0] 这里设置USB的时钟频率为48M,具体的参照手册。 ldr r0,=MPLLCON ldr r1,=0x5c011 str r1,[r0] 这里最终将系统时钟频率设置为400M,MPLLCON是控制FCLK和Fin之间的关系,查看数据手册如下: 这里给出了m,p,s三个参数是如何来的,我们再看 这里设置为0x5c011也就是0101 1100 0000 0001 0001,根据数据位,可以计算得到s=1,p=1+2=3,m=172+8=100,又因为我们的晶振为12MHZ,所以mpll=fclk=(2*100*12)/(3*2)=400MHZ。 三.cpu_init_crit及MMU CP15协处理器配置分析 下面,第186行: #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif 如果没有定义CONFIG_SKIP_LOWLEVEL_INIT,那就跳转到cpu_init_crit这个函数,这里使用了bl,也就是下一条指令的执行地址,存放在lr链接寄存器里面,说明子函数运行结束之后,使用mov pc lr,程序还是要回到这里继续执行,切过去,第212行: /* *flush v4 I/D caches */ mov r0,#0 mcr p15,0, r0, c7, c7, 0 /* flush v3/v4 cache*/ mcr p15,0, r0, c8, c7, 0 /* flush v4 TLB */ /* *disable MMU stuff and caches */ mrc p15,0, r0, c1, c0, 0 bic r0,r0, #0x00002300 @ clear bits 13, 9:8(--V- --RS) bic r0,r0, #0x00000087 @ clear bits 7, 2:0(B--- -CAM) orr r0,r0, #0x00000002 @ set bit 2 (A) Align orr r0,r0, #0x00001000 @ set bit 12 (I) I-Cache mcr p15,0, r0, c1, c0, 0 首先来看看mcr和mrc这两个指令吧,查到如下: MRC {条件}协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,{协处理器操作码2} MCR {条件}协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,{协处理器操作码2} arm的cp15协处理器时只能够被mcr和mrc两个指令操作的,这里我们查看datasheet: 这里由于是cp15,所以8到11位是1111,各个位对应的意思也可以去datesheet查到。这里不赘述了。 mcr p15,0, r0, c7, c7, 0 /* flush v3/v4 cache*/ mcr p15,0, r0, c8, c7, 0 /* flush v4 TLB */ 这里先对r0清零以后,再对c7和c8进行清零,而c7和c8分别对应什么呢,可以继续看下手册里面的寄存器编号: 可以看到表格里面c7,c8在MMU中的作用是告诉缓存和写缓存控制以及TLB控制,其实c7和c8是两个只写寄存器,这里就是清除cache和写缓存,以及清除TLB就是这么做的。 mrc p15,0, r0, c1, c0, 0 bic r0,r0, #0x00002300 @ clear bits 13, 9:8(--V- --RS) bic r0,r0, #0x00000087 @ clear bits 7, 2:0(B--- -CAM) orr r0,r0, #0x00000002 @ set bit 2 (A) Align orr r0,r0, #0x00001000 @ set bit 12 (I) I-Cache mcr p15,0, r0, c1, c0, 0 这段呢,其实就很明了了,首先将c0和c1的值读给r0,然后分别清除对应的位,分别是0到2位,7位,8,9,13位,这些位是干嘛的呢?为什么要清楚这些位。查找datasheet看到c1,下面有两个表格,清除的位和下面用orr指令设置的位我都标注出来了。 可以看到表格里面c7,c8在MMU中的作用是告诉缓存和写缓存控制以及TLB控制,其实c7和c8是两个只写寄存器,这里就是清除cache和写缓存,以及清除TLB就是这么做的。 mrc p15,0, r0, c1, c0, 0 bic r0,r0, #0x00002300 @ clear bits 13, 9:8(--V- --RS) bic r0,r0, #0x00000087 @ clear bits 7, 2:0(B--- -CAM) orr r0,r0, #0x00000002 @ set bit 2 (A) Align orr r0,r0, #0x00001000 @ set bit 12 (I) I-Cache mcr p15,0, r0, c1, c0, 0 这段呢,其实就很明了了,首先将c0和c1的值读给r0,然后分别清除对应的位,分别是0到2位,7位,8,9,13位,这些位是干嘛的呢?为什么要清楚这些位。查找datasheet看到c1,下面有两个表格,清除的位和下面用orr指令设置的位我都标注出来了。 总结一下这一步具体做了哪些事情,首先禁止MMU,禁止对齐检查,禁止整个cache,选择为小尾数,取消系统保护,取消rom保护,禁止指令cache,选择低端的异常中断向量。然后再设置对齐检查,因为我们的ALIGN是四字节对齐的,然后再使能指令cache。看来简单的禁止MMU不是那么简单的。。。 四.lowlevel_init.S分析 第235行: mov ip, lr bl lowlevel_init 首先,ip是一个内部调用暂时寄存器,我们现在是在cpu_init_crit函数里面,而一开始从start_code跳转到cpu_init_crit里面的时候,lr保存的是从cpu_init_crit用于返回到start_code的地址,这里再跳转到lowlevel_init的时候我们需要将lr的值暂存到ip里面,待会儿从lowlevel_init回来的时候,再用ip把保存的地址还给lr,这样我们再进行跳转就回到start_code里面去了。说白了,就是函数的嵌套调用方法。 下面我们切换到lowlevel_init中去,这个文件在board/mini2440/mini2440下,打开。 第114行: lowlevel_init: /* memorycontrol configuration */ /* make r0relative the current location so that it */ /* readsSMRDATA out of FLASH rather than memory ! */ ldr r0, =SMRDATA ldr r1, =CONFIG_SYS_TEXT_BASE sub r0, r0, r1 三段注释部分说的是这部分是内存控制的配置,请使r0相对当前位置从FLASH读出SMRDATA,而不是从存储器里面。(暂时不明白啥意思) ldr r0, =SMRDATA 这里是一个伪指令,SMRDATA使用了后面的在low文件最后的.ltorg伪指令,将其作为了一个数据缓冲池,而SMRDATA就是数据缓冲池的名称。见文件最后第132行开始: .ltorg /* the literal pools origin */ SMRDATA: .word(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) .word((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) .word((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) .word((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) .word((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) .word((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) .word((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) .word((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) .word((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
上一篇:U-boot-2014.04移植到MINI2440(1) 初步探索移植
下一篇:U-boot-2014.04移植到MINI2440(2) Readme翻译分析
推荐阅读最新更新时间:2024-10-24 05:26
设计资源 培训 开发板 精华推荐
- CN3722太阳能MPPT充电板
- STK984-091AGEVB,STK984-091A-E 三相BLDC电机驱动器混合评估板
- LTC1591 的典型应用 - 具有 4 象限电阻器的 14 位并行低毛刺乘法 DAC
- ADP7104CPZ-REDYKIT、ADP7104CP-EVALZ LFCSP RedyKit 用于 ADP7104 1.5V 低压差 (LDO) 线性稳压器
- ESP01S-0.96OLED显示屏
- TRK-KEA64、Kinetis KEA64 StarterTRAK MCU 带 256B EEPROM
- ADA4530-1R-EBZ-TIA,ADA4530-1 8 引脚 SOIC 封装 SP 放大器评估板
- 3528幻彩LED灯板
- 使用 Infineon Technologies AG 的 OM7604ST 的参考设计
- HUANCAI