(三) u-boot 啟動分析_第一階段
本文重點在於分析 uboot 啟動流程以及 uboot 自身的細節,比如棧空間的劃分、如何設定 tag 、如何新增一個自定義命令等。但是不涉及基本的硬體驅動的分析,比如記憶體初始化、時鐘初始化、mmu 、nandflash 等等這些詳細細節不是我們的重點。
u-boot 版本: uboot 1.1.6
使用的開發板: JZ2440V3
一、連結指令碼
uboot1.1.6 的連結指令碼 u-boot.lds 位於 u-boot-1.1.6\board\smdk2410 目錄下:
- ENTRY(_start)
- SECTIONS
- {
-
. = 0x00000000; //起始地址
-
. = ALIGN(4); //4位元組對齊
-
.text : //test指程式碼段,上面3行標識是不佔用任何空間的
- {
-
cpu/arm920t/start.o (.text) //這裡把start.o放在第一位就表示把start.s編譯時放到最開始,這就是為什麼把uboot燒到起始地址上它肯定執行的是start.s
- *(.text)
- }
-
. = ALIGN(4); //前面的 “.” 代表當前值,是計算一個當前的值,是計算上面佔用的整個空間,再加一個單元就表示它現在的位置
-
.rodata : { *(.rodata) }
- . = ALIGN(4);
- .data : { *(.data) }
- . = ALIGN(4);
- .got : { *(.got) }
- . = .;
- __u_boot_cmd_start = .;
- .u_boot_cmd : { *(.u_boot_cmd) }
- __u_boot_cmd_end = .;
- . = ALIGN(4);
- __bss_start = .;
- .bss : { *(.bss) }
- _end = .;
- }
arm-Linux-ld -Bstatic -T u-boot.lds -Ttext 0x33F80000 start.o ...
0x33F80000 在 board/smdk2410/config.mk 中定義,為 TEXT_BASE = 0x33F80000 (連結地址)
整個 uboot 的入口 _start 包含在 cpu/arm920t/start.S 中
二、第一階段
uboot 的第一階段主要工作是作基本的初始化工作,例如關看門狗、初始化時鐘、初始化 sdram 以及程式碼重定位,為第二階段做準備。這裡的程式碼都是沒有經過移植的原始碼~!
1、設定異常向量
-
.globl _start /*宣告一個符號可被其它檔案引用,相當於聲明瞭一個全域性變數,.globl與.global相同*/
-
_start: b reset /* 復位,b是不帶返回的跳轉(bl是帶返回的跳轉),意思是無條件直接跳轉到reset標號出執行程式*/
-
ldr pc, _undefined_instruction /* 未定義指令向量 ldr相當於mov操作*/
- ldr pc, _software_interrupt /* 軟體中斷向量 */
-
ldr pc, _prefetch_abort /* 預取指令異常向量 */
- ldr pc, _data_abort /* 資料操作異常向量 */
-
ldr pc, _not_used /* 未使用 */
-
ldr pc, _irq /* irq中斷向量 */
-
ldr pc, _fiq /* fiq中斷向量 */
- /* 中斷向量表入口地址 */
-
_undefined_instruction: .word undefined_instruction /*就是在當前地址,即_undefined_instruction 處存放 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 //word偽操作用於分配一段字記憶體單元(分配的單元都是字對齊的),並用偽操作中的expr初始化
-
_fiq: .word fiq /* now 16*4=64 */
- .balignl 16,0xdeadbeef
ldr pc, _undefined_instruction
_undefined_instruction:.word undefined_instruction
感覺真是在賣弄,兩條指令連起來的結果就是,CPU 會跳轉到 undefined_instruction 連結地址處去執行(sdram裡)。
那麼其實,一條 ldr pc,=undefined_instruction 就夠了,它是位置有關碼,絕對跳轉。
或許,uboot 的作者別有用意我沒看透,不知道這是不是個伏筆。在u-boot2015裡,就只有一個 reset 一個異常入口了。
2、進入管理SVC模式
- reset:
- /*
- * set the cpu to SVC32 mode
- */
- mrs r0,cpsr
- bic r0,r0,#0x1f
- orr r0,r0,#0xd3
- msr cpsr,r0
有時候我們會碰到 CPSR_C ,它其實就是 CPSR 的低 8 位而已。
I:1-禁止irq中斷 0-允許irq中斷
F:1-禁止fiq中斷 1-允許fiq中斷
T:1-Thumb 0-arm 指令集
M0-M4 : 工作模式
說了這麼多,前邊兩條指令,先將 cpsr 低 5位 清零,然後或上 1101 0011B
禁止了 irq 和 fiq 中斷,工作在 arm 指令集,管理模式。
3、關看門狗
- #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
- ldr r0, =pWTCON
- mov r1, #0x0
- str r1, [r0]
- /*
- * mask all IRQs by setting all bits in the INTMR - default
- */
- mov r1, #0xffffffff
- ldr r0, =INTMSK
- str r1, [r0]
- # if defined(CONFIG_S3C2410)
- ldr r1, =0x3ff
- ldr r0, =INTSUBMSK
- str r1, [r0]
- # endif
5、設定時鐘
- /* FCLK:HCLK:PCLK = 1:2:4 */
- /* default FCLK is 120 MHz ! */
- ldr r0, =CLKDIVN
- mov r1, #3
- str r1, [r0]
- /*
- * flush v4 I/D caches
- */
- mov r0, #0
- mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
- mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
協處理器 p15 在2410的資料手冊附錄有介紹
或者參考:http://blog.sina.com.cn/s/blog_858820890102v1gc.html
7、關 mmu
- /*
- * disable MMU stuff and caches
- */
- mrc p15, 0, r0, c1, c0, 0
- bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
- bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
- orr r0, r0, #0x00000002 @ set bit 2 (A) Align
- orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
- mcr p15, 0, r0, c1, c0, 0
8、初始化 sdram 控制器
- .globl lowlevel_init
- lowlevel_init:
- /* memory control configuration */
- /* make r0 relative the current location so that it */
- /* reads SMRDATA out of FLASH rather than memory ! */
- ldr r0, =SMRDATA
- ldr r1, _TEXT_BASE
- sub r0, r0, r1
- ldr r1, =BWSCON /* Bus Width Status Controller */
- add r2, r0, #13*4
- 0:
- ldr r3, [r0], #4
- str r3, [r1], #4
- cmp r2, r0
- bne 0b
- /* everything is fine now */
- mov pc, lr
- .ltorg
- /* the literal pools origin */
- SMRDATA:
- .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
- .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
- .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
- .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
- .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
- .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
- .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
- .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
- .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
- .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
- .word 0x32
- .word 0x30
- .word 0x30
9、程式碼重定位
- relocate: /* relocate U-Boot to RAM */
- adr r0, _start /* 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 stack_setup
- ldr r2, _armboot_start
- ldr r3, _bss_start
- sub r2, r3, r2 /* r2 <- size of armboot */
- add r2, r0, r2 /* r2 <- source end address */
- copy_loop:
- 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
拷貝範圍:_start 至 _bss_start 前,拷貝到 0x33f80000 處。
33f80048 <_bss_start>:
33f80048: 33fb064c
0x33fb064c - 0x33f80000 = 193K ,什麼意思呢?(整個 uboot 除了 bss 段) > 4k,如果是 nandflash 啟動的話,SRAM只會複製NAND Flash儲存器的前4K位元組過去執行,我們需要複製的程式碼為193K,顯然需要初始化 nandflash 並從裡面讀取 uboot 到核心,而我們到這裡還沒有初始化NandFlash,,從而得到預設 uboot是從norflash啟動,不支援 nandflash 啟動。
10、設定棧
- stack_setup:
- ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
- sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
- sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
- #ifdef CONFIG_USE_IRQ
- sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
- #endif
- sub sp, r0, #12 /* leave 3 words for abort-stack */
- clear_bss:
- ldr r0, _bss_start /* find start of bss segment */
- ldr r1, _bss_end /* stop here */
- mov r2, #0x00000000 /* clear */
- clbss_l:str r2, [r0] /* clear loop... */
- add r0, r0, #4
- cmp r0, r1
- ble clbss_l
- #define CFG_MALLOC_LEN (CFG_ENV_SIZE + 128*1024)
- #define CFG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */
- #define CFG_GBL_DATA_SIZE 128
- #define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */
- #define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */
- 0x34000000:
- (512K) 存放 uboot
- 0x33F80000: TEXT_BASE
- (64K+128K == 192K) malloc區
- 0x33F50000:
- (128bytes) global data區,後邊會提到主要放的gd、bd全域性結構體
- 0x33F4FF80:
- (8K) IRQ+FIQ的棧
- 0x33F4DF80:
- (12byte) abort-stack,棧溢位
- 0x33F4DF74: sp
- clear_bss:
- ldr r0, _bss_start /* find start of bss segment */
- ldr r1, _bss_end /* stop here */
- mov r2, #0x00000000 /* clear */
- clbss_l:str r2, [r0] /* clear loop... */
- add r0, r0, #4
- cmp r0, r1
- ble clbss_l
- ldr pc, _start_armboot
- start_armboot: .word start_armboot
跳轉到 sdram 裡的 start_armboot 函式執行。
總結: