u-boot分析 四 (程序入口start.S)

u-boot分析 四 (程序入口start.S)

 

注:部分内容摘抄自网络,如有问题,请联络博主。

 

本文内容:了解以stars.S为开始的ARM汇编程序部分。

 

回顾前几篇博文,咱们见识过了u-boot的目录结构,另外简要分析了u-boot.lds脚本文件的link原理。而今天我们要来听听嵌入式程序君告诉咱们的第一句

 

正式开始之前,我们需要准备三样东西:

  1. u-boot source code
  2. 常用ARM指令集
  3. Source Insight(用于trace code,使用方法略过,不会问百度)

 

bootloader通常stage1stage2两步骤,u-boot也不例外。

  1. Stage1:依赖于CPU体系结构的代码(如设备初始化代码等)通常都放在这个程序段,且可以用汇编语言来实现;
  2. stage2:通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。

具体的说,

  1. Stage1 start.S代码结构
    u-bootstage1代码通常放在start.S文件中,用汇编语言写成,其主要代码部分如下:
    (1) 定义入口。由于一个可执行文件必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROMFlash)的0x0地址。因此,必须通知编译器以使其知道这个入口,该工作可通过修改链接器脚本(.lds文件)来完成。
    (2) 设置异常向量(Exception Vector)。
    (3) 设置CPU的速度、时钟频率及终端控制寄存器。
    (4) 初始化内存控制器。
    (5) ROM中的代码复制到RAM中。
    (6) 初始化堆栈。
    (7) 转到RAM中执行,该工作可使用指令ldr pc来完成。
  2. Stage2 C语言代码部分
    ./arch/arm/lib/board.c中的board_init_r()C语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数主要完成如下操作:
    (1) 调用一系列的初始化函数。
    (2) 初始化Flash设备。
    (3) 初始化系统内存分配函数。
    (4) 如果目标系统拥有NAND设备,则初始化NAND设备。
    (5) 如果目标系统有显示设备,则初始化该类设备。
    (6) 初始化相关网络设备,填写IPMAC地址等。
    (7) 进去命令循环(即整个boot的工作循环),接收用户从串口输入的命令,然后进行相应的工作。

事不宜迟,我们赶紧打开start.S

./arch/arm/cpu/slsiap/s5p4418/start.S

/*

 * armboot - Startup Code for NXPxxxx/ARM Cortex CPU-core

 */

 

#include <asm-offsets.h>

#include <config.h>

#include <version.h>

#include <asm/system.h>

#include <linux/linkage.h>

 

/*

 *************************************************************************

 *

 * Exception vectors as described in ARM reference manuals

 *

 * replace arm/lib/vectors.S

 *

 *************************************************************************

 */

    .globl  _stext 

    /*程序的全局入口,《u-boot分析 三》中u-boot.lds设置此入口地址为0x00000000*/

_stext:

    b   reset

    /*参阅《常用ARM指令集及汇编》可知,b为跳转指令,跳转到reset函数处,reset在后面*/

 

    /*ARM体系结构规定在上电复位后的起始位置,必须有8条连续的跳转指令,通过硬件实现。他们就是异常向量表*/

    /*ldr,用于加载32bit的立即数或一个地址值到指定寄存器*/

    ldr pc, _undefined_instruction /*未定义指令异常,0x04*/

    ldr pc, _software_interrupt    /*软中断异常,0x08*/

    ldr pc, _prefetch_abort        /*内存操作异常,0x0c*/

    ldr pc, _data_abort            /*数据异常,0x10*/

    ldr pc, _not_used              /*未使用,0x14*/

    ldr pc, _irq                   /*慢速中断异常,0x18*/

    ldr pc, _fiq                   /*快速中断异常,0x1c*/

 

/*.word的意思是将后边的符号所对应的32bit值赋予前面的符号*/

/*而如下的七条语句,后面的符号正好是对应的中断异常服务程序的入口地址*/

/*这七个中断服务程序位于./arch/arm/cpu/slsiap/s5p4418/vector.S*/

_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

 

    .balignl 16,0xdeadbeef

    /*16bytes对齐,并且使用0xdeadbeef填充*/

 

    /*.balignl.balign的变体

    .align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。

    .balign的作用同.align

    .align {alignment} {,fill} {,max}

    其中:

        alignment用于指定对齐方式,可能的取值为2的次幂,缺省为4

        fill是填充内容,缺省用0填充。

        max是填充字节数最大值,如果填充字节数超过max,就不进行对齐*/

 

/*

 *************************************************************************

 *

 * Text and section base

 *

 *************************************************************************

 */

 

.globl TEXT_BASE

/*全局定义TEXT_BASE*/

TEXT_BASE:

    .word   CONFIG_SYS_TEXT_BASE

    /*TEXT_BASE使用.word赋予的值为CONFIG_SYS_TEXT_BASE,而CONFIG_SYS_TEXT_BASE是在

    u-boot/include/configs/s5p4418_urbetter.h中定义,值为0x42c00000*/

 

/*

 * These are defined in the board-specific linker script(u-boot.lds中定义),可参看前面的博客

 */

.globl _bss_start_ofs

_bss_start_ofs:

    .word __bss_start - _stext

 

.globl _bss_end_ofs

_bss_end_ofs:

    .word __bss_end - _stext

 

.globl _end_ofs

_end_ofs:

    .word _end - _stext

 

/*

 *************************************************************************

 *

 * Reset handling

 *

 *************************************************************************

 */

 

    .globl reset

    /*这里便是reset函数的入口*/

    /*其实在CPU一上电以后就是跳到这里执行的*/

 

reset:

    bl  save_boot_params

    /*call save_boot_params,此函数在下面有定义,但是实际do nothing*/

 

    /*

     * set the CPU to SVC32 mode,即管理模式

     */

    /*对状态寄存器CPSR的修改要按照:读出-修改-写回的顺序来执行*/

    /*

    31  30  29  28 ----- 7   6   -   4   3   2   1   0

    N   Z   C   V        I   F       M4  M3  M2  M1 M0

                                     0   0   0   0   0     User26 模式

                                     0   0   0   0   1     FIQ26 模式

                                     0   0   0   1   0     IRQ26 模式

                                     0   0   0   1   1     SVC26 模式

                                     1   0   0   0   0     User 模式

                                     1   0   0   0   1     FIQ 模式

                                     1   0   0   1   0     IRQ 模式

                                     1   0   0   1   1     SVC 模式

                                     1   0   1   1   1     ABT 模式

                                     1   1   0   1   1     UND 模式

                                     1   1   1   1   1     SYS 模式

    */

 

    mrs r0, cpsr

    /*读出cpsr的值*/

    bic r0, r0, #0x1f

    /*清零低5*/

    orr r0, r0, #0xd3

    /*0xd3,即1 1 0 1 0 0 1 1,即为SVC模式,禁止IRQ,FIQ中断(bit6,7)*/

    msr cpsr,r0

    /*写回cpsr使其生效*/

 

    /* the mask ROM code should have PLL and others stable */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

/*UT4418 u-boot source code中没有define CONFIG_SKIP_LOWLEVEL_INIT,所以如下两条命令会执行*/

    bl  cpu_init_cp15

    /*bl为跳转指令,即call cpu_init_cp15函数,该函数在下面定义,主要功能是

    Invalidate L1 I/Ddisable MMU stuff and I-cache*/

 

    bl  cpu_init_crit

    /*继续调用cpu_init_crit函数,函数定义在下面,该函数中只有一句函数,即b lowlevel_init

    lowlevel_init函数的具体功能,此处先略过*/

#endif

 

#ifdef CONFIG_RELOC_TO_TEXT_BASE

/*u-boot/include/configs/s5p4418_urbetter.hdefine CONFIG_RELOC_TO_TEXT_BASE*/

 

relocate_to_text:

/*程序继续执行,此程序段便是要将ROM中的code copyTEXT_BASE处,即从0x0开始的数据copy0x42c00000*/

 

    /*

     * relocate u-boot code on memory to text base

     * for nexell arm core (add by jhkim)

     */

 

    adr r0, _stext              /* r0 <- current position of code   */

    ldr r1, TEXT_BASE           /* test if we run from flash or RAM */

    cmp r0, r1                  /* don't reloc during debug         */

    beq clear_bss

 

    ldr r2, _bss_start_ofs

    add r2, r0, r2              /* r2 <- source end address         */

 

copy_loop_text:

    ldmia   r0!, {r3-r10}       /* copy from source address [r0]    */

    stmia   r1!, {r3-r10}       /* copy to   target address [r1]    */

    cmp r0, r2                  /* until source end addreee [r2]    */

    ble copy_loop_text

 

    ldr r1, TEXT_BASE           /* restart at text base */

    mov pc, r1

    /*程序从TEXT_BASE处开始执行*/

 

clear_bss:

    ldr r0, _bss_start_ofs

    ldr r1, _bss_end_ofs

    ldr r4, TEXT_BASE           /* text addr */

    add r0, r0, r4

    add r1, r1, r4

    mov r2, #0x00000000         /* clear */

 

clbss_l:str r2, [r0]            /* clear loop... */

    add r0, r0, #4

    cmp r0, r1

    bne clbss_l

 

#ifdef CONFIG_MMU_ENABLE

/*同样在u-boot/include/configs/s5p4418_urbetter.h中已经define*/

 

    bl  mmu_turn_on

    /*ROMRAMcopy完成后,继续调用 mmu_turn_on函数,此函数位于/u-boot/arch/arm/cpu/slsiap/s5p4418/mmu_asm.S

    主要功能是打开MMU,详细过程需要进一步trace code*/

#endif

 

    ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

    /*u-boot/include/configs/s5p4418_urbetter.h

    define CONFIG_SYS_INIT_SP_ADDR = CONFIG_SYS_TEXT_BASE,即0x42c00000*/

 

    bic sp, sp, #7

    /* 8-byte alignment for ABI compliance */

 

    sub sp, #GD_SIZE

    /* allocate one GD above SP */

 

    bic sp, sp, #7

    /* 8-byte alignment for ABI compliance */

 

    mov r9, sp

    /* GD is above SP */

 

    mov r0, #0

    bl  board_init_f

    /*call board_init_f, /u-boot/arch/arm/lib/board.c*/

 

    mov sp, r9

    /* SP is GD's base address */

 

    bic sp, sp, #7

    /* 8-byte alignment for ABI compliance */

 

    sub sp, #GENERATED_BD_INFO_SIZE

    /* allocate one BD above SP */

 

    bic sp, sp, #7

    /* 8-byte alignment for ABI compliance */

 

    mov r0, r9

    /* gd_t *gd */

 

    ldr r1, TEXT_BASE

    /* ulong text */

 

    mov r2, sp

    /* ulong sp */

 

    bl  gdt_reset

    /*调用gdt_reset函数初始化gdtu-boot/arch/arm/cpu/slsisp/s5p4418/Cpu.c*/

 

    /* call board_init_r(gd_t *id, ulong dest_addr) */

    mov r0, r9                          /* gd_t */

    ldr r1,  =(CONFIG_SYS_MALLOC_END)   /* dest_addr for malloc heap end */

    /* call board_init_r */

    ldr pc, =board_init_r

    /* this is auto-relocated! */

    /*board_init_r变开始进入Stage2/u-boot/arch/arm/lib/board.c*/

 

#else   /* CONFIG_RELOC_TO_TEXT_BASE */

 

    bl  _main

#endif

 

/*------------------------------------------------------------------------------*/

 

ENTRY(c_runtime_cpu_setup)

/*

 * If I-cache is enabled invalidate it

 */

#ifndef CONFIG_SYS_ICACHE_OFF

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

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

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

#endif

/*

 * Move vector table

 */

    /* Set vector address in CP15 VBAR register */

    ldr     r0, =_stext

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

 

    bx  lr

 

ENDPROC(c_runtime_cpu_setup)

 

/*************************************************************************

 *

 * void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3)

 *  __attribute__((weak));

 *

 * Stack pointer is not yet initialized at this moment

 * Don't save anything to stack even if compiled with -O0

 *

 *************************************************************************/

ENTRY(save_boot_params)

    bx  lr          @ back to my caller

ENDPROC(save_boot_params)

    .weak   save_boot_params

 

/*************************************************************************

 *

 * cpu_init_cp15

 *

 * Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless

 * CONFIG_SYS_ICACHE_OFF is defined.

 *

 *************************************************************************/

ENTRY(cpu_init_cp15)

    /*

     * Invalidate L1 I/D

     */

    /*MRC,协处理器寄存器到ARM寄存器的数据传输指令。MRC将协处理器寄存器中的数据传送到

    ARM处理器的寄存器中。若协处理器不能成功执行该操作,将产生未定义异常中断*/

 

    mov r0, #0

    /*set up for MCR*/

    mcr p15, 0, r0, c8, c7, 0

    /*invalidate TLBs,使TLBs无效*/

    mcr p15, 0, r0, c7, c5, 0

    /*invalidate icache,使icache无效*/

    mcr p15, 0, r0, c7, c5, 6

    /*invalidate BP array*/

 

    /*如下两条命令,参考http://blog.csdn.net/itxiebo/article/details/50957808

    了解即可,甚至可以直接跳过分析*/

    dsb

    isb

 

    /*

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

#ifdef CONFIG_SYS_ICACHE_OFF

    bic r0, r0, #0x00001000

    /*clear bit 12 (I) I-cache*/

#else

    orr r0, r0, #0x00001000

    /*set bit 12 (I) I-cache*/

#endif

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

    mov pc, lr

    /*back to my caller,返回调用处*/

ENDPROC(cpu_init_cp15)

 

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

/*************************************************************************

 *

 * CPU_init_critical registers

 *

 * setup important registers

 * setup memory timing

 *

 *************************************************************************/

ENTRY(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.

     */

    b   lowlevel_init

    /*go setup pll,mux,memory*/

    /*u-boot/arch/arm/cpu/slsiap/s5p4418/low_init.S*/

 

ENDPROC(cpu_init_crit)

#endif

 

回顾全文,我们总结一下start.S都干了些什么?

  1. 首先定义程序入口_stext
  2. 然后定义了异常向量表
  3. 一堆初始化,e.g. PLL, MUX, Memory
  4. Copy代码从ROMRAM
  5. MMU on
  6. 最后跳转到C入口

 

参考博客:

http://blog.chinaunix.net/uid-22891435-id-380150.html

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值