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通常stage1和stage2兩步驟,u-boot也不例外。

  1. Stage1:依賴於CPU體系結構的代碼(如設備初始化代碼等)通常都放在這個程序段,且可以用彙編語言來實現;
  2. stage2:通常用C語言來實現,這樣可以實現複雜的功能,而且有更好的可讀性和移植性。

具體的說,

  1. Stage1 start.S代碼結構
    u-boot的stage1代碼通常放在start.S文件中,用彙編語言寫成,其主要代碼部分如下:
    (1) 定義入口。由於一個可執行文件必須有一個入口點,並且只能有一個全局入口,通常這個入口放在ROM(Flash)的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) 初始化相關網絡設備,填寫IP、MAC地址等。
    (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/D,disable 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.h中define CONFIG_RELOC_TO_TEXT_BASE*/

relocate_to_text:
/*程序繼續執行,此程序段便是要將ROM中的code copy到TEXT_BASE處,即從0x0開始的數據copy到0x42c00000處*/

    /*
     * 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
    /*ROM到RAM的copy完成後,繼續調用 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函數初始化gdt,u-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代碼從ROM到RAM
  5. MMU on
  6. 最後跳轉到C入口

參考博客:
http://blog.chinaunix.net/uid-22891435-id-380150.html


發佈了29 篇原創文章 · 獲贊 44 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章