3-uboot-spl代码流程
[uboot] (第三章)uboot流程——uboot-spl代碼流程
2016年10月28日 16:24:14閱讀數:2077以下例子都以project X項目tiny210(s5pv210平臺,armv7架構)為例。
[uboot] uboot流程系列:?
[project X] tiny210(s5pv210)上電啟動流程(BL0-BL2)?
[uboot] (第一章)uboot流程——概述?
[uboot] (第二章)uboot流程——uboot-spl編譯流程
建議參考文章?
[kernel 啟動流程] (第二章)第一階段之——設置SVC、關閉中斷?
[kernel 啟動流程] (第六章)第一階段之——打開MMU?
ARM的CP15協處理器的寄存器
建議先看《[project X] tiny210(s5pv210)上電啟動流程(BL0-BL2)》,根據例子了解一下上電之后的BL0\BL1\BL2階段,以及各個階段的運行位置,功能。
========================================================================================================
一、說明
1、uboot-spl入口說明
通過uboot-spl編譯腳本project-X/u-boot/arch/arm/cpu/u-boot-spl.lds
ENTRY(_start)- 1
所以uboot-spl的代碼入口函數是_start?
對應于路徑project-X/u-boot/arch/arm/lib/vector.S的_start,后續就是從這個函數開始分析。
2、CONFIG_SPL_BUILD說明
前面說過,在編譯SPL的時候,編譯參數會有如下語句:?
project-X/u-boot/scripts/Makefile.spl
- 1
所以說在編譯SPL的代碼的過程中,CONFIG_SPL_BUILD這個宏是打開的。?
uboot-spl和uboot的代碼是通用的,其區別就是通過CONFIG_SPL_BUILD宏來進行區分的。
二、uboot-spl需要做的事情
CPU初始剛上電的狀態。需要小心的設置好很多狀態,包括cpu狀態、中斷狀態、MMU狀態等等。?
在armv7架構的uboot-spl,主要需要做如下事情
- 關閉中斷,svc模式
- 禁用MMU、TLB
- 芯片級、板級的一些初始化操作?
- IO初始化
- 時鐘
- 內存
- 選項,串口初始化
- 選項,nand flash初始化
- 其他額外的操作
- 加載BL2,跳轉到BL2
上述工作,也就是uboot-spl代碼流程的核心。
三、代碼流程
1、代碼整體流程
代碼整體流程如下,以下列出來的就是spl核心函數。?
_start———–>reset————–>關閉中斷?
………………………………|?
………………………………———->cpu_init_cp15———–>關閉MMU,TLB?
………………………………|?
………………………………———->cpu_init_crit————->lowlevel_init————->平臺級和板級的初始化?
………………………………|?
………………………………———->_main————–>board_init_f_alloc_reserve & board_init_f_init_reserve & board_init_f———->加載BL2,跳轉到BL2?
board_init_f執行時已經是C語言環境了。在這里需要結束掉SPL的工作,跳轉到BL2中。
2、_start
上述已經說明了_start是整個spl的入口,其代碼如下:?
arch/arm/lib/vector.S
- 1
- 2
- 3
- 4
- 5
會跳轉到reset中。?
注意,spl的流程在reset中就應該被結束,也就是說在reset中,就應該轉到到BL2,也就是uboot中了。?
后面看reset的實現。
3、reset
建議先參考[kernel 啟動流程] (第二章)第一階段之——設置SVC、關閉中斷,了解一下為什么要設置SVC、關閉中斷以及如何操作。
代碼如下:?
arch/arm/cpu/armv7/start.S
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
4、cpu_init_cp15
建議先參考[kernel 啟動流程] (第六章)第一階段之——打開MMU兩篇文章的分析。?
cpu_init_cp15主要用于對cp15協處理器進行初始化,其主要目的就是關閉其MMU和TLB。?
代碼如下(去掉無關部分的代碼):?
arch/arm/cpu/armv7/start.S
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
5、cpu_init_crit
cpu_init_crit,進行一些關鍵的初始化動作,也就是平臺級和板級的初始化。其代碼核心就是lowlevel_init,如下?
arch/arm/cpu/armv7/start.S
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
所以說lowlevel_init就是這個函數的核心。?
lowlevel_init一般是由板級代碼自己實現的。但是對于某些平臺來說,也可以使用通用的lowlevel_init,其定義在arch/arm/cpu/lowlevel_init.S中?
以tiny210為例,在移植tiny210的過程中,就需要在board/samsung/tiny210下,也就是板級目錄下面創建lowlevel_init.S,在內部實現lowlevel_init。(其實只要實現了lowlevel_init了就好,沒必要說在哪里是實現,但是通常規范都是創建了lowlevel_init.S來專門實現lowlevel_init函數)。
在lowlevel_init中,我們要實現如下:?
* 檢查一些復位狀態?
* 關閉看門狗?
* 系統時鐘的初始化?
* 內存、DDR的初始化?
* 串口初始化(可選)?
* Nand flash的初始化
下面以tiny210的lowlevel_init為例(這里說明一下,當時移植tiny210的時候,是直接把kangear的這個lowlevel_init.S文件拿過來用的)?
這部分代碼和平臺相關性很強,簡單介紹一下即可?
board/samsung/tiny210/lowlevel_init.S
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
當串口中打印出‘OK’的字符的時候,說明lowlevel_init已經執行完成。?
system_clock_init是初始化時鐘的地方。 mem_ctrl_asm_init這個函數是初始化DDR的地方。后續應該有研究一下這兩個函數。這里先有個印象。
6、_main
spl的main的主要目標是調用board_init_f進行先前的板級初始化動作,在tiny210中,主要設計為,加載BL2到DDR上并且跳轉到BL2中。DDR在上述lowlevel_init中已經初始化好了。?
由于board_init_f是以C語言的方式實現,所以需要先構造C語言環境。?
注意:uboot-spl和uboot的代碼是通用的,其區別就是通過CONFIG_SPL_BUILD宏來進行區分的。?
所以以下代碼中,我們只列出spl相關的部分,也就是被CONFIG_SPL_BUILD包含的部分。?
arch/arm/lib/crt0.S
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
代碼拆分如下:?
(1)因為后面是C語言環境,首先是設置堆棧
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
關于CONFIG_SPL_STACK,我們通過前面的文章《[project X] tiny210(s5pv210)上電啟動流程(BL0-BL2)》?
我們已經知道s5pv210的BL1(spl)是運行在IRAM的,并且IRAM的地址空間是0xD002_0000-0xD003_7FFF,IRAM前面的部分放的是BL1的代碼部分,所以把IRAM最后的空間用來當作堆棧。?
所以CONFIG_SPL_STACK定義如下:?
include/configs/tiny210.h
- 1
注意:上述還不是最終的堆棧地址,只是暫時的堆棧地址!!!
(2)為GD分配空間
bl board_init_f_alloc_reserve @@ 把堆棧的前面一部分空間分配給GD使用mov sp, r0 @@ 重新設置堆棧指針SP/* set up gd here, outside any C code */mov r9, r0 @@ 保存GD的地址到r9寄存器中- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
注意:雖然sp的地址和GD的地址是一樣的,但是堆棧是向下增長的,而GD則是占用該地址后面的部分,所以不會有沖突的問題。?
關于GD,也就是struct global_data,可以簡單的理解為uboot的全局變量都放在了這里,比較重要,所以后續有會寫篇文章說明一下global_data。這里只需要知道在開始C語言環境的時候需要先為這個結構體分配空間。?
board_init_f_alloc_reserve實現如下?
common/init/board_init.c
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
還有一點,其實GD在spl中沒什么使用,主要是用在uboot中,但在uboot中的時候還需要另外分配空間,在講述uboot流程的時候會說明。
(3)初始化GD空間?
前面說了,此時r0寄存器存放了GD的地址。
- 1
board_init_f_init_reserve實現如下?
common/init/board_init.c?
編譯SPL的時候_USE_MEMCPY宏沒有打開,所以我們去掉了_USE_MEMCPY的無關部分。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
(4)跳轉到板級前期的初始化函數中?
如下代碼
- 1
board_init_f需要由板級代碼自己實現。?
在這個函數中,tiny210主要是實現了從SD卡上加載了BL2到ddr上,然后跳轉到BL2的相應位置上?
tiny210的實現如下:?
board/samsung/tiny210/board.c
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
關于copy_bl2_to_ddr的實現,也就是如何從SD卡或者nand flash上加載BL2到DDR上的問題,請參考后續文章《[project X] tiny210(s5pv210)代碼加載說明》。
到此,SPL的任務就完成了,也已經跳到了BL2也就是uboot里面去了。
總結
以上是生活随笔為你收集整理的3-uboot-spl代码流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1-uboot流程——概述
- 下一篇: 4-uboot编译流程