1. 引入 start.S
(1)通過對連結腳本的分析可知,整個程式的入口取決于連結腳本中 ENTRY 聲明的地方。在 uboot.lds 中可以看到 ENTRY(_start),是以 _start 就是整個程式的入口,而 _start 所在的檔案就是整個程式的起始檔案。通過搜尋可知,_start 存在 start.S 中,是以 start.S 就是整個程式的起始檔案。
2. 頭檔案
代碼:28 ~ 33 行
#include <config.h>
#include <version.h>
#if defined(CONFIG_ENABLE_MMU)
#include <asm/proc/domain.h>
#endif
#include <regs.h>
(1)#include <config.h>
include/config.h 檔案不是源碼中自帶的,而是通過配置檔案 mkconfig 自動生成的。它的内容很簡單,如下所示:
#include <configs/x210_sd.h>
通過分析可知,這裡包含的是 include/configs/x210_sd.h 檔案(這個檔案是整個 uboot 移植時的配置檔案,裡面有很多宏)。是以分析 start.S 時,要考慮 include/configs/x210_sd.h 。
(2)#include <version.h>
include/version.h 檔案的内容如下所示:
#include "version_autogenerated.h"。
include/version_autogenerated.h 頭檔案是在編譯時自動生成的,這裡面隻有一個宏定義,如下所示:
#define U_BOOT_VERSION "U-Boot 1.3.4"
這個宏來自于主 Makefile 的配置值,并且在程式中被調用。在 uboot 啟動過程中,序列槽列印出的 uboot 的版本号就來源于這裡。
(3)#include <asm/proc/domain.h>
include/asm 是一個軟連結,在 uboot 中本來是沒有的,是在配置時建立的(詳情參考 mkconfig),實際指向 include/asm-arm 目錄。經過以上分析可知,這裡實際包含的是 include/asm-arm/proc/domain.h 檔案。
(4)#include <regs.h>
include/regs.h 也是一個軟連接配接,也是在配置時建立的,實際指向 include/s5pc110.h 。
(5)從這裡就可以知道之前在配置時建立的符号連結的作用,如果沒有這些符号連結,編譯時根本通不過,因為找不到頭檔案。(是以uboot不能在windows的共享檔案夾下配置編譯的原因是windows中沒有符号連結)
(6)思考:這裡為什麼不直接包含,而是要用符号連結的方式?
這樣的設計主要是為了可移植性。因為如果直接包含,則start.S檔案和CPU架構(和硬體)相關了,可移植性就差了,假如把uboot移植到mips架構下,則start.S源代碼中所有的頭檔案包含全部要修改。但是用了符号連結之後,start.S中源代碼就不需要改,隻需要在移植時,根據硬體确定在符号連結的指向,這樣就具有可移植性了。
3. 啟動代碼的 16 位元組頭部
代碼:49 ~ 54 行
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
.word 0x2000
.word 0x0
.word 0x0
.word 0x0
#endif
(1)從代碼中可以看出:若定義了 CONFIG_EVT1 并且沒有定義 CONFIG_FUSED,那麼就定義 4 位元組空間。
(2)在裸機部分,SD 卡啟動(或 Nand 啟動)啟動時,需要 16 位元組的校驗頭(mkv210image.c 就是用來計算這個校驗頭的),但是當時并沒有詳細考慮過這個問題,是因為:dnw 方式啟動時不需要這 16 位元組;SD 卡啟動時,mkv210image.c 會給鏡像加上 16 位元組的校驗頭。
(3)這裡隻是在開頭位置放置了 16 位元組的填充占位,這裡的占位隻是保證了鏡像頭部有 16 位元組,并不保證它的内容是對的,這 16 個位元組的值還需要後面去重新計算和填充的。
4. 異常向量表建構
代碼:56 ~ 83 行
.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
_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 */
.global _end_vect
_end_vect:
(1)異常向量表是 CPU 設計時決定的,是硬體決定的。
(2)異常向量表的所有異常都應被處理,否則程式會飛。
(3)複位異常處理的代碼時:
b reset
CPU 複位後真正去執行的有效的代碼是 reset 處的代碼,是以符号 reset 處的代碼才是真正的有意義的代碼的開始地方。
5. 有點意思的 deadbeef
代碼:85 行
.balignl 16,0xdeadbeef
(1)該條指令是讓目前位址按 16 位元組對其,若沒有對齊,用 0xdeadbeef 數字來填充,直到對齊。
(2)0xdeadbeef 沒有什麼特别的意義,但是内容很有意思,剛好組成了一個單詞 dead beep (壞牛肉)。
(3)為什麼要對齊呢?有時候是為了提高通路效率,有時候是硬體的要求。
6. 一些定義
代碼:86 ~ 135 行
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
_TEXT_BASE:
.word TEXT_BASE
/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
_TEXT_PHY_BASE:
.word CFG_PHY_UBOOT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
#if defined(CONFIG_USE_IRQ)
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
(1)TEXT_BASE
第 100 行的這個 TEXT_BASE 是在 Makefile 配置階段時的那個 TEXT_BASE,也就是連結時指定的 uboot 中的那個連結位址,它的值時 0xc3e00000 。
在源代碼中和配置的 Makefile 中,很多變量是互相關聯的,有些符号的值可以從 Makefile中 傳遞到源代碼中。
(2)CFG_PHY_UBOOT_BASE
uboot 在DDR中的實體位址 —— 0x33e00000,它的定義放在 include/configs/x210_sd.h,如下所示:
#define CFG_PHY_UBOOT_BASE MEMORY_BASE_ADDRESS + 0x3e00000
(3)_armboot_start
這個會在重定位時用到
(4)_bss_start、_bss_end
用于清理 bss 段用的