6410 uboot启动引导分析

http://keyewan.blog.163.com/blog/static/1898272332011763164586/

 

以下用以记录分析过程,如有错误,欢迎指正。

强调,内容与三星提供的uboot有更改的地方,因为外接外设的区别。

纯代码分析,以后会传上uboot的内存分布图和功能结构图。

代码可以在arm9网站下载,mini6410的,本代码也是基于它的改的。

本文章将分析介绍uboot代码的第一阶段和第二阶段。

 

1.start.s代码分析(第一阶段)

/* 以下是具有arm特色的异常向量表,为使能中断异常的时候处理用 */

--------------------

.globl _start
_start: b reset
 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

--------------------

 

/* 当发生中断异常时,跳转到pc会跳转到.word的后面地址处 处理异常,

   undefined异常由arm核译码单元检测,并触发未定义指令异常请求;

   软中断放在0x8地址,arm中使用swi指令时触发,多用在系统库的编写;

   prefetch异常,预取指中止异常,产生的原因未知,导致正在取的指令无法正常取出,这里需要注意流水线造成的pc值 ;

   data中止,无法获取数据,产生的原因有可能是内存未准备好,或是cache未命中等一些原因产生的异常;

   0x14暂时未使用;

   0x18地址存放中断异常,一般我们的处理器都会引出很多的中断线,在这里所要做的就是判断系统中断,注册中断,初始化中断,调用中断函数等等;

   0x1c地址为_fiq快速中断,一个系统在中断流水线上可能产生很多中断,但快中断只会有一个

*/

--------------------

_undefined_instruction:
 .word undefined_instruction
_software_interrupt:
 .word software_interrupt
_prefetch_abort:
 .word prefetch_abort
_data_abort:
 .word data_abort
_not_used:
 .word not_used
_irq:
 .word irq
_fiq:
 .word fiq
_pad:
 .word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:

 .balignl 16,0xdeadbeef

--------------------

 

/* _TEXT_BASE标号所代表的是uboot代码实际的运行地址,我们的uboot最终不可能运行在s3c6410的引导镜像区,对于s3c6410

   系统来说,如果nand flash启动方式,系统会把0xc000000里面前4KB的内容映射到引导镜像区,即0x0地址,但是我们需要把

   uboot代码放到我们的SDRAM,原因是我们代码里面需要对变量做更改并且增加代码执行效率

   好吧,说多了,上面的看不明白当废话,下面的含义其实就是执行程序的运行地址,.word后面的值TEXT_BASE在编译的时候,

   通过向编译器传递参数获得,-DTEXT_BASE方式向编译器传递宏参 

*/

--------------------

_TEXT_BASE:
 .word TEXT_BASE

--------------------

/* 在uboot里面会开启MMU,使用到虚拟地址 */

--------------------

_TEXT_PHY_BASE:
 .word CFG_PHY_UBOOT_BASE

--------------------

/* 这个不解释也是可以的 */

--------------------

.globl _armboot_start
_armboot_start:
 .word _start

--------------------

/* 下面的代码__bss_start的值的定义在u-boot.lds脚本里面定义的,虽然没给值,但是你要知道文件的大小和位置是由

   编译器指定的,那么还需要我们告诉它值吗?所以没值胜有值啦

 */

--------------------

.globl _bss_start
_bss_start:
 .word __bss_start

.globl _bss_end
_bss_end:
 .word _end

--------------------

/* uboot开始执行代码处即在这里了,下面的代码在干些事情,使得cpu的模式为管理模式,话又说回来,不是管理模式msr、mrs官方给

   的解释也是用不了的,何况,系统上电的时候就是管理模式,CPRS的值也是固定的,模式这部分代码有些小多余。 */

--------------------

reset:

 mrs r0,cpsr
 bic r0,r0,#0x1f
 orr r0,r0,#0xd3
 msr cpsr,r0

--------------------

 

/* 以下标号所在处的代码比较多,将做逐步分析,这段代码主要的工作也就是改了一些硬件寄存器和内存初始化工作 */

--------------------

cpu_init_crit:

--------------------

 /*
  刷新指令和数据缓存,mcr的意思是把arm寄存器的值赋值给coprocesser寄存器,拿第一条指令来说,

  p15代表协处理器,0为一定的值,指令中0b0000四位来表示,现在无具体作用,如果不是0则结果未知,后面的r0是即将写入

  c7目标寄存器中的值,后面还有个c7所代表的意思为额外操作码,如果不是c0,则表示的是同一个寄存器的不同物理寄存器,因为

  同一个寄存器的名字并不代码通一个物理内存,我们在学rpsr的时候应该知道这点,最后的0提供附加信息,用于区分同一寄存器的

 不同物理寄存器,如无附加信息,请保持为0值,否则结果不可预测

 下面三行代码不难看出,c7、c8的值被清为0,为什么要清为零呢,你需要去看arm1176jzf-sarm核了,其中是有说明的,不再累述,

 arm1176jzf-sarm核芯片手册下载地址httop://www.arm.com
  */

--------------------
 mov r0, #0
 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

--------------------

 /*
  实在不想解释这段,因为以前看过芯片手册的解释,且不止一遍,对于这里面要更改的内容就是不能全部记下来,和工作有关了,

  不能全心搞这块内容,最多2个月左右的时间能回来回顾一下了。总之还是去查arm11核芯片手册,因为以下改的内容是协处理器

  c1,那么你就该去查c1是用来干什么的。查看得知,是控制寄存器,查看手册是online books12.2.2 Primary register allocation

  一节,其中13,9,8位为 V、R、S:V位是对高端异常向量表的支持,如果选择0异常向量表为0x00000000-0x0000001c,如果选择

 1异常向量表就是FFFF0000-FFFF001c;R位用于ROM保护的,具体的还要与c5里面的配合,这都是MMU惹的祸,很烦,但是现在

  我们还没有讲到MMU,所以为什么这样做,也必须到讲到MMU的时候才见分晓了,S在这里面的意思也是用于系统保护的,和MMU

  又是有很大的关系,好吧,后面会找MMU算账的,这里就先不深入了,接下来再分析下下面的指令含义

  bic r0, r0, #0x00000087 @ clear bits 7, 2:0(B--- -CAM) 的B位为0表示支持小little-endian,1表示支持big-endian格式的系统内存

  CAM为第三位,M为0代表禁止MMU,反之打开,A代表地址对齐检查,0代表禁止,C代表指令数据cache控制,0为禁止

  orr r0, r0, #0x00000002 @ set bit 2 (A) Align 这段指令又比较犯贱了,打开地址对齐检查了,这是应该的O(∩_∩)O~,后面又

  设置12位为1,含义是如果数据cache和指令cache是分开的话,这里面置1的含义将会打开指令cache*/

--------------------
 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

--------------------

 

/* c15在s3c6410上有特殊作用,它是内存端口映射32位寄存器,MMU在开关的时候发生作用,且优先级最高

   这里的0x70000000为peri port的基地址,0x13的二进制为0x10011,0x10011的意思为256M,代表映射的

   大小为256M,0x10010为128M。假如你没开MMU,那么下面代码就不需要写了,写了的话PHY和Peri port

   映射的地址相同。但是MMU ON,下面代码是一定要写的。

   使用C15的方法是:

   1.Opcode_1 set to 0

   2.CRn set to c15

   3.CRm set to c2

   4.Opcode_2 set to 4

 */

--------------------

 /* Peri port setup */
 ldr r0, =0x70000000
 orr r0, r0, #0x13
     mcr p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)

--------------------

/* 下面是一条跳转指令,代码实在不想贴,因为功能都是老生常谈的,比如说点亮LED灯、关闭watchdog、关闭中断、系统时钟初始

   nand flash初始化、内存控制器初始化。不过说实在的,去仔细分析这些初始化的过程,对于你对如何控制硬件有很大的帮助,

   对于这个函数,所要说的东西太多,会在后面的文章中单独分析它,现在先知道功能就好。

*/

--------------------

bl lowlevel_init

--------------------

 

/* 跳转出来以后,继续执行下面的代码,下面的代码是判断程序是否已经在ram中了,在的话就不拷贝,直接跳转到after_copy了,否则

   继续执行下面的代码 */

--------------------

 ldr r0, =0xff000fff
 bic r1, pc, r0  /* r0 <- current base addr of code */
 ldr r2, _TEXT_BASE  /* r1 <- original base addr in ram */
 bic r2, r2, r0  /* r0 <- current base addr of code */
 cmp     r1, r2                  /* compare r0, r1                  */
 beq     after_copy  /* r0 == r1 then skip flash copy   */

--------------------

 

/* 判断是否从NAND启动,其实还可以从SD卡启动,onenand,有兴趣自己研究这些启动方式吧 ,下面是通过函数copy_from_nand
   拷贝代码到ram中*/

--------------------

#ifdef CONFIG_BOOT_NAND
 mov r0, #0x1000
 bl copy_from_nand
#endif

--------------------

 

/* SD卡启动方式 */

--------------------

#ifdef CONFIG_BOOT_MOVINAND
 ldr sp, _TEXT_PHY_BASE
 bl movi_bl2_copy
 b after_copy
#endif

--------------------

 

/* 点灯 */

--------------------

after_copy:
 ldr r0, =ELFIN_GPIO_BASE
 ldr r1, =0xC00
 str r1, [r0, #GPPDAT_OFFSET]
 ldr r1, [r0, #GPFPUD_OFFSET]
 bic r1, r1, #0xc0000000
 orr r1, r1, #0x80000000
 str r1, [r0, #GPFPUD_OFFSET]
 ldr r1, [r0, #GPFDAT_OFFSET]
 orr r1, r1, #0x8000
 str r1, [r0, #GPFDAT_OFFSET]
 ldr r1, [r0, #GPFCON_OFFSET]
 bic r1, r1, #0xc0000000
 orr r1, r1, #0x40000000
 str r1, [r0, #GPFCON_OFFSET]

--------------------

 

/* 打开MMU功能了,下班了,下次再细化介绍吧。 */

--------------------

#ifdef CONFIG_ENABLE_MMU
enable_mmu:
 /* enable domain access */
 ldr r5, =0x0000ffff
 mcr p15, 0, r5, c3, c0, 0  @ load domain access register

 /* Set the TTB register */
 ldr r0, _mmu_table_base
 ldr r1, =CFG_PHY_UBOOT_BASE
 ldr r2, =0xfff00000
 bic r0, r0, r2
 orr r1, r0, r1
 mcr p15, 0, r1, c2, c0, 0

 /* Enable the MMU */
mmu_on:
 mrc p15, 0, r0, c1, c0, 0
 orr r0, r0, #1   /* Set CR_M to enable MMU */
 mcr p15, 0, r0, c1, c0, 0
 nop
 nop
 nop
 nop
#endif

--------------------

 

/* 堆栈初始化代码,这也是老生常谈的不用说了 */

--------------------

skip_hw_init:
 /* Set up the stack          */
stack_setup:
#ifdef CONFIG_MEMORY_UPPER_CODE
 ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0xc)
#else
 ldr r0, _TEXT_BASE  /* upper 128 KiB: relocated uboot   */
 sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */
 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
 sub sp, r0, #12  /* leave 3 words for abort-stack    */

#endif

--------------------

 

/* 清楚BSS段代码为0 */

--------------------

clear_bss:
 ldr r0, _bss_start  /* find start of bss segment        */
 ldr r1, _bss_end  /* stop here                        */
 mov  r2, #0x00000000  /* clear                            */

clbss_l:
 str r2, [r0]  /* clear loop...                    */
 add r0, r0, #4
 cmp r0, r1
 ble clbss_l

--------------------

 

/* 跳转到代码的uboot代码的第二个阶段 */

--------------------

 ldr pc, _start_armboot

_start_armboot:
 .word start_armboot

--------------------

 

2.第二阶段代码分析(代码在lib_arm目录下的board.c里面,start_armboot函数)

下次分析吧,下班了。。。想想头疼啊,还有前面的VFP、象棋算法没有去研究呢。

好吧,我本来觉得可以继续分析下去,但一看第二阶段代码太多,且不容易理解,所以,再次决定下次单独开辟章节写第二阶段的代码分析。但是,我们首先应该知道的是第二阶段在干什么:

1.硬件初始化

2.网络传输功能

3.命令交互功能

4.环境变量

 

等有时间,会针对这些问题在新的文章中深入浅出说明以下问题:

1.硬件初始化的详细过程,比如说nand_flash、UART(通过原理图、datasheet、寄存器控制等说明)

2.网络传输功能(将介绍DM9000网卡芯片的驱动程序)

3.命令交互(uboot中是如何添加命令的,如何增加自己的命令调用)

4.环境变量的存储和调用,以及uboot代码中的一些重要环境变量

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值