u-boot分析 四 (程序入口start.S)
注:部分內容摘抄自網絡,如有問題,請聯絡博主。
本文內容:瞭解以stars.S爲開始的ARM彙編程序部分。
回顧前幾篇博文,咱們見識過了u-boot的目錄結構,另外簡要分析了u-boot.lds腳本文件的link原理。而今天我們要來聽聽嵌入式程序君告訴咱們的第一句“話”。
正式開始之前,我們需要準備三樣東西:
- u-boot source code
- 常用ARM指令集
- Source Insight(用於trace code,使用方法略過,不會問百度)
bootloader通常stage1和stage2兩步驟,u-boot也不例外。
- Stage1:依賴於CPU體系結構的代碼(如設備初始化代碼等)通常都放在這個程序段,且可以用彙編語言來實現;
- stage2:通常用C語言來實現,這樣可以實現複雜的功能,而且有更好的可讀性和移植性。
具體的說,
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來完成。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都幹了些什麼?
- 首先定義程序入口_stext
- 然後定義了異常向量表
- 一堆初始化,e.g. PLL, MUX, Memory等
- Copy代碼從ROM到RAM
- MMU on
- 最後跳轉到C入口
參考博客:
http://blog.chinaunix.net/uid-22891435-id-380150.html
完