天天看點

uboot啟動第一階段——start.S(一)

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 段用的

繼續閱讀