從上一章的鏈接腳本分析中,我們知道了uboot的程序是從ENTRY(_start)開始的

在整個uboot工程下搜索 _start ,可以找到一個 start.S 文件包含了這個label,因此uboot啟動的分析從這個文件開始

頭文件分析

#include <config.h>
#include <version.h>
#if defined(CONFIG_ENABLE_MMU)
#include <asm/proc/domain.h>
#endif
#include <regs.h>

start.S 一開始include的config.h這個頭文件是由$(TOPDIR)/mkconfig自動生成的,具體生成的腳本如下

#
# Create board specific header file
#
if [ "$APPEND" = "yes" ] # Append to existing config file
then
echo >> config.h
else
> config.h # Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/$1.h>" >>config.h

config.h這個頭文件中的內容如下,configs/x210_sd.h中包含的是與x210特性相關的用於適配的宏

/* Automatically generated - do not edit */
#include <configs/x210_sd.h>

通過搜索這個頭文件,我們可以發現CONFIG_ENABLE_MMU被定義,所以會包含asm/proc/domain.h這個頭文件

greedyhao@greedyhao-PC:.../qt_x210v3s_160307/uboot$ cat include/configs/x210_sd.h | grep CONFIG_ENABLE_MMU
#define CONFIG_ENABLE_MMU
#ifdef CONFIG_ENABLE_MMU
#ifdef CONFIG_ENABLE_MMU

通過ls -l可以發現這個頭文件是proc-armv文件夾的一個軟連接

greedyhao@greedyhao-PC:.../qt_x210v3s_160307/uboot$ ls -il include/asm/ | grep proc
6430221 lrwxrwxrwx 1 greedyhao greedyhao 9 3月 15 09:31 proc -> proc-armv

之所以使用proc而不是proc-armv,是為了可移植性。

試想一下,在移植時需要去把proc-xxx一個個修改是件多麼痛苦的事,而且這種啟動代碼應該可重用的部分很多,使用軟連接的方式可以減少很多不必要的工作

啟動文件的校驗頭

uboot 選擇 SD/NAND 啟動方式,需要啟動文件提供一個16位元組的校驗頭,start.S 就在開頭填充了16位元組的空間

#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
.word 0x2000
.word 0x0
.word 0x0
.word 0x0
#endif

在 uboot 編譯完,得到可執行文件後,還需要補充這16位元組的校驗和,uboot才能啟動

三星有提供程序用來計算這個校驗和,下面簡單看看

計算校驗和

程序的用法如下

Usage: mkbl1 <source file> <destination file> <size>

在使用這個程序的時候,會向程序的 main 函數中傳遞一個參數數組 *argv[] ,而且 argv[0] = mkbl1,argv[1] = source file,argv[2] = destination file,argv[3] = size,這些都是基本常識,就不多說了

mkbl1 在得到文件的大小後,先會分配一個緩衝區,準備用來存放需要處理的文件

BufLen = atoi(argv[3]);
Buf = (char *)malloc(BufLen);
memset(Buf, 0x00, BufLen);

準備好緩衝區後,就把需要處理的文件讀入,使用 fseek 計算文件長度,再使用 fread 將文件讀入

// 已刪除錯誤處理
fp = fopen(argv[1], "rb");

fseek(fp, 0L, SEEK_END);
fileLen = ftell(fp);
fseek(fp, 0L, SEEK_SET);

nbytes = fread(Buf, 1, BufLen, fp);
fclose(fp);

計算校驗和的時候需要跳過前16個位元組,然後從第9個位元組開始寫入計算出來的校驗和

a = Buf + 16;
for(i = 0, checksum = 0; i < BufLen - 16; i++)
checksum += (0x000000FF) & *a++;

a = Buf + 8;
*( (unsigned int *)a ) = checksum;

寫入也和讀取類似,先 fopen 再使用 fwrite 寫入,最後釋放掉緩存區的空間

異常向量表

.globl _start
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
...
.global _end_vect
_end_vect:
.balignl 16,0xdeadbeef

異常向量表是當程序發生異常時的處理方式,在向量表製作完後,使用 balignl 偽指令,讓內存16位元組對齊,加速硬體訪問;至於 0xdeadbeef 代表用來補位垃圾數據

複位向量設置

_TEXT_BASE:
.word TEXT_BASE

定義了一個 _TEXT_BASE 標籤用來存放複位向量,主要是用在處理器初始化和 stack 的設置

至於 TEXT_BASE 之前介紹過,由 makefile 文件導入

x210_sd_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk


個人博客

公眾號:greedyhao


推薦閱讀:
相关文章