U-boot在开发板上移植过程详解(2)---U-boot实现源码分析(第一阶段)
时间:2011-05-22 来源:☆&寒 烟☆
前边,我们说了,一般的bootloader都分为两个阶段。我在讲U-boot实现源码分析时,也是按照这连个阶段来分析,如果对这两个阶段不清楚,请看前边的博客。好了,开始今天的主题:U-boot在开发板上移植过程详解(2)---U-boot实现源码分析(start.S分析)
第一阶段:
1)一些基本的硬件初始化工作
u-boot对应的第一阶段代码放在cpu/arm920t/start.S文件中,入口代码如下:
| 
            .globl _start                 ;global声明一个符号可被其它文件引用,相当于声明了一个全局变量,.globl与.global相同 
            ;.word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并用伪操作中的expr初始化。 _undefined_instruction: .word undefined_instruction ;就是在当前地址,即_undefined_instruction 处存放 undefined_instruction 
            _software_interrupt:      .word software_interrupt | 
这部分就是异常向量表。当系统上电或复位后,将执行第一条指令,即跳转到标签为reset的代码处执行,具体如下:
| 
          reset:                                   ;设置CPU为SVC32管理模式 
          #if defined(CONFIG_S3C2400)   ;关闭看门狗 
          #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) 
              mov     r1, #0xffffffff                    ;屏蔽所有中断 
          #ifndef CONFIG_SKIP_LOWLEVEL_INIT | 
上面的代码将CPU设为管理模式,关闭看门狗,屏蔽中断并设置中断,最后调用cpu_init_crit函数进行cpu的初始化,代码如下:
| 
          cpu_init_crit:                                 ;清除指令和数据缓存 mcr p15, 0, r0, c8, c7, 0 ;mcr指令用于将ARM处理器寄存器的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则 ;产生未定义指令异常。其中协处理器操作码1和协处理器操作码2为协处理器将要执行的操作,目的寄存器 ;为ARM处理器的寄存器,源寄存器1和源寄存器2均为协处理器的寄存器。 
              mrc    p15, 0, r0, c1, c0, 0            ;mrc 协处理器寄存器到ARM处理器寄存器的数据传送指令 
              mov    ip, lr                                 ;设置SDRAM控制器,与具体的目标板相关 | 
在这个函数中做了一下工作:清除指令与数据缓存,禁用MMU与数据指令缓存,最后调用lowlevel_init函数设置SDRAM控制器。该函数的实现与具体的目标板有关的。
2)准备RAM空间
所谓准备RAM空间,就是初始化内存芯片,使它可用。 在board/smdk2410/lowlevel.init.S就是这个作用,要注意这时的代码,数据都保存在NOR Flash上,内存中还没有,所以读取数据时要变换地址,如下:
| 
          _TEXT_BASE: 
          .globl lowlevel_init 
              ;现在起三行进行地址变化,因为这时候内存中还没有数据,不能使用连接程序时确定的地址来读取数据     mov pc, lr 
              .ltorg 
          SMRDATA:                                   ;13个寄存器的值 .word … … | 
这里做完以后,就要将整个U-boot的代码都复制到SDRAM中,这些又都在start.S中实现,如下:
| 
          relocate:                                     ;将u-boot复制到RAM中 
              ldr     r2, _armboot_start             ;_armboot_start在前边已经定义,是第一条指令的运行地址 
          copy_loop: | 
接下来,就要设置栈,栈的设置灵活性很大,只要让sp寄存器指向一段没有使用的内存即可。
| 
          stack_setup: | 
3)跳转到第二阶段代码的C入口点
在跳转之前,还要清除BSS段(初始值为0,无初始值的全局变量,静态变量放在BSS段),代码如下:
| 
          clear_bss: 
          clbss_l:str    r2, [r0]                      ;往BSS段中写入0值 | 
现在,c函数的运行环境已经完全准备好了,通过如下命令直接跳转(这之后,程序才在内存中执行),它将调用lib_arm/board.c中的start_armboot函数(这是一个C语言函数),这是第二阶段的入口点:
| ldr pc, _start_armboot _start_armboot: .word start_armboot | 
在第二阶段代码中,将进行更多的初始化工作,如对各种设备和接口的初始化,串口终端的初始化等。如果没有设置自动运行,则最终将进入一个循环,在循环内读取用户输入的命令并执行,这些会在下一节详细介绍。










