u_boot_2013.01启动流程分析(一)(for exynos4412)

一、EXYNOS4412上电启动流程

u_boot_2013.01启动流程分析(一)(for exynos4412)

可以看出,不管是固化在irom里的代码还是三星加密代码都是不需要我们系统/驱动工程师所深究的,所以我们弄清楚了启动流程,接下来来看具体代码。

二、代码段最前端的start.S文件

u-boot上电一启动首先运行的是start.S文件,这是u-boot的第一阶段的代码

start.s:

.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

 

/*_start是一个函数的起始地址,也是编译、链接后程序的起始地址。(此为bootloader第一阶段的代码)U_boot运行的第一/条命令是b  Reset 异常向量表(位置固定,不可更改)*/

u_boot_2013.01启动流程分析(一)(for exynos4412)

_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 */

 

/*用 . word 修饰 函数入口地址是让pc程序计数器能够跳到更远的地址(异常向量表异常函数入口地址)*/

_TEXT_BASE:

       .word     CONFIG_SYS_TEXT_BASE  (0x43E00000)

 

/*

 * These are defined in the board-specificlinker script.

 */

_bss_start_ofs:

       .word  __bss_start  - _start// (去掉bss段uboot大小)

 

_image_copy_end_ofs:

       .word    __image_copy_end- _start(.txt + .rodata + .data + .u_boot_list)

 

_bss_end_ofs:

       .word __bss_end__ - _start //(整个uboot大小)

 

_end_ofs:

       .word _end - _start (.txt + .rodata +.data + .u_boot_list + .rel.dyn + .dynsym)

/* the actual reset code*/

/*程序一开始,跳到Reset这运行函数        save_boot_params 是官方指定函数名称*/

reset:

bl    save_boot_params

      /*

           *set the cpu to SVC32 mode        把ARM核的工作模式设置为超级用户模式    */

       mrs r0,cpsr

       bic  r0,r0, #0x1f

       orr  r0,r0, #0xd3

       msr cpsr,r0

       

/*告诉ARM核异常向量表所在的地址为低地址

低地址0x0~0xffff0000大于就是高地址*/

       /* Set V=0 in CP15 SCTRL register - forVBAR to point to vector */

       mrc p15,0, r0, c1, c0, 0    @Read CP15 SCTRL Register

       bic  r0,#CR_V            @ V = 0

       mcr p15,0, r0, c1, c0, 0    @ Write CP15 SCTRLRegister

 

/*获得异常向量表所在的地址,将异常向量表的基地址写入P15协处理器的C12寄存器中------------即告诉ARM核异常向量表所在的地方。        Set vector address in CP15 VBARregister */

       ldr  r0,=_start

       mcr p15,0, r0, c12, c0, 0  @Set VBAR

/* 关闭MMucache的原因是它们必须在内存初始化之后才能使用,需要用时再开启*/

       bl    cpu_init_cp15//(关MMU和cache)

       bl    cpu_init_crit//(初始化系统时钟和内存)

      

/*跳转到main函数执行bootloader第二阶段的代码。       arch/arm/lib/crt0.S*/

       bl    _main

/*以上是start.S文件的主体部分跳转到main函数执行bootloader第二阶段的代码,以下是一些跳转的具体实现*/

save_boot_params:

       bx   lr                   @ back to my caller

       .weak     save_boot_params

 

/*Reset 跳到这之后又跳回去

. weak 的作用是弱化这个函数

(原因是该函数可能会被传参,便于别人覆盖,但设计师并不能确定,所以以弱化的方式先规范死函数名。)*/

cpu_init_cp15:

       /*

        *Invalidate L1 I/D    开启cache作为ARM核从内存中取数据的缓冲,提高ARM核提取数据的速度

        */

       mov       r0,#0                   @ set up for MCR

       mcr p15,0, r0, c8, c7, 0    @ invalidate TLBs

       mcr p15,0, r0, c7, c5, 0    @ invalidate icache

       mcr p15,0, r0, c7, c5, 6    @ invalidate BP array

       mcr    p15, 0, r0, c7, c10, 4       @ DSB

       mcr     p15, 0, r0, c7, c5, 4  @ ISB

/*MMU是虚拟地址到物理地址的一个映射,现阶段没有操作系统,不需要使用到MMU*/

/ * disable MMU stuff and caches */

       mrc p15,0, r0, c1, c0, 0

       bic  r0,r0, #0x00002000  @ clear bits 13 (--V-)

       bic  r0,r0, #0x00000007  @ clear bits 2:0 (-CAM)

       orr  r0,r0, #0x00000002  @ set bit 1 (--A-) Align

       orr  r0,r0, #0x00000800  @ set bit 11 (Z---) BTB

       orr  r0,r0, #0x00001000  @ set bit 12 (I) I-cache

       mcr p15,0, r0, c1, c0, 0

       mov       pc,lr                    @ back to my caller

 

 

cpu_init_crit:

       /*

        *Jump to board specific initialization...

        *The Mask ROM will have already initialized

        *basic memory. Go here to bump up clock rate and handle

        *wake up conditions.

        不带返回的跳转,需要在下面保存lr寄存器的值*/

       b     lowlevel_init              @ go setup pll,mux,memory

/* lr寄存器的值保存起来(lr中保存的实际是bl main这句程序的地址*/

board/samsung/origen/lowlevel_init.S

lowlevel_init:

       push      {lr}

       /*

        *If U-boot is already running in ram, no need to relocate U-Boot.

        *Memory controller must be configured before relocating U-Boot

        *in ram.

        判断现在程序是否在内存中运行,如果是的话,就不需要执行下面的初始化时钟与初始化内存的程序了。

        具体做法:取出当前pc程序计数器指针的值,后24位清除(在IRAM中则是0x02000000,在内存中则是0x40000000)

        

        把__TEXT_BASE0x43e00000)低24位清除进行比较,相同则程序已运行在内存中*/

       ldr  r0,=0x0ffffff        /* r0 <- Mask Bits*/

       bic  r1,pc, r0             /* pc <- currentaddr of code */

                                          /* r1<- unmasked bits of pc */

       ldr  r2,_TEXT_BASE         /* r2 <- originalbase addr in ram */

       bic  r2,r2, r0              /* r2 <- unmaskedbits of r2*/

       cmp       r1,r2                   /* compare r1, r2 */

       beq 1f                  /* r0 == r1 then skip sdraminit */

/* 初始化系统时钟,让cpu核运行的更快,提高主频*/

       /* init system clock */

       bl system_clock_init

/*初始化内存,让内存可以用,为后面在内存里的操作做准*/

/* Memoryinitialize */

       bl mem_ctrl_asm_init

/*初始化串口的一些gpio管脚设为UART模式*/ 

1:

       /* for UART */

       bl uart_as`-/``m_init

       pop {pc}

至此,start.S文件与exynos4412u-boot第一阶段的代码至此完结

三、总结


第一阶段u_boot 实现功能1、将第二阶段的U_boot代码搬移到内存中指定位置。 2、将pc指针指向内存中的第二阶段代码的起始位置开始执行第二阶段的代码。


(本人经验技术有限,如有错误请在留言中指正,谢谢大家,共同进步!)