imx6ul:uboot-2013.10启动过程解析
1.源碼結構分析
???? 首先一個問題,老版本的u-boot是沒有SPL這個文件的,新版u-boot開始包含SPL文件,原來u-boot啟動比如放到nand中,在cpu內部有一個stepping stone,可以拷貝nand中的u-boot到ram中運行,然后u-boot自己再啟動第二階段在對應內存中好到系統的image啟動。現在加了這個SPL之后,我的理解這是一個u-boot的loader。及cpu上電后,首先運行這個spl,然后通過這個spl再將u-boot放到對應的位置運行,之后的操作就和老版本基本一樣了。至于為什么這樣做,暫時還不明白,后期再研究下。
編譯成功的u-boot-2013.10共有19個子目錄,大約15個有用的文件,其中各個子目錄和重要文件功能見下表:
| 名稱 | 類型 | 功能說明 |
| api | 通用 | U-boot提供的一些接口函數 |
| arch | 平臺相關 | 當前U-BOOT重要的目錄,arch下每個子目錄代表一種處理器類型 |
| board | 平臺相關 | 里面有很多支持的開發板型號,這里關注具體開發板和config.mk |
| common | 通用 | 主要跟U-BOOT的命令有關,cmd_xxx.c以及環境變量的處理代碼env_xxx.c |
| spl | 平臺相關 | u-boot的第一階段相關,搬運第二階段代碼到內存中 |
| disk | 通用 | 磁盤驅動的分區處理代碼 |
| doc | 說明文檔 | 可以用來做配置參考 |
| drivers | 通用 | 設備的驅動程序,每種類型一個子目錄包括網卡,USB,LCD等 |
| dts | 通用 | 設備樹的控制,主要是由于LINUX 3.X中去除了很多冗余的代碼,引入device tree,許多硬件細節可以直接傳遞給LINUX,是新的東西 |
| examples | 通用 | 一些示例程序 |
| fs | 通用 | 文件系統支持 |
| include | 通用 | 頭文件和開發板的配制,configs子目錄重要 |
| lib | 通用 | 通用的庫文件 |
| Licenses | 通用 | 可以忽略。。。 |
| nand_spl | 平臺相關 | 支持了部分平臺的nand啟動 |
| net | 通用 | 網絡相關的代碼,小型的協議棧 |
| post | 通用 | 加電自檢程序 |
| scripts | 通用 | 腳本程序 |
| test | 通用 | 測試程序 |
| tools | 通用 | 工具,mkimage就在這里 |
| boards.cfg | 文件,平臺相關 | 修改添加開發板配置現在在此處 |
| Makefile MAKEALL config.mk rules.mk mkconfig | 文件,通用 | 整個U-BOOT編譯過程的規則文件 |
| kbuild mkconfig | 文件,通用 | 對Makefile功能的補充,使得編譯更加高效 |
| 其余 | 文件,通用 | 介紹文檔以及其他 |
??? 移植工作主要集中在一些編譯規則文件,還有board和arch目錄下。
2 Makefile分析
??? u-boot的README里面其實講的很清楚u-boot的移植過程,翻譯過來如下:
??? 第一步:在boards.cfg里面添加自己的開發板,必須按照現有的規則添加。
??? 第二步:為自己的開發板建立一個目錄,在目錄下添加你需要的文件,這目錄下必須要有以下幾個文件,Makefile,<board>.c,flash.c和u-boot.lds
???? 第三步:為你的建立一個新的配置文件“include/configs/<board>.h”
??? 第四步:輸入“make<board>_config”
??? 第五步:make
??? 第六步:調試并解決出現的問題(當然,這一步遠比聽起來的難很多)
??? Makefile的分析可以了解整個U-boot的代碼結構是怎樣的,文件是如何編譯、鏈接的。
2.1分析配置過程第一步
??? 在編譯的時候第一步是輸入:make wandboard_config,當輸入這個指令的時候,Makefile就會調用以下語句:
??? %_config:: unconfig
???????? @$(MKCONFIG) -A $(@:_config=)
??? %通配符匹配到執行xxx_config的時候,就調用下面的@$(MKCONFIG),這個MKCONFIG可以搜索在以下定義:
??? MKCONFIG := $(SRCTREE)/mkconfig
??? export MKCONFIG
2.2分析mkconfig文件
??? mkconfig為$(SRCTREE)/目錄下的mkconfig文件,就是我們源碼目錄下的mkconfig文件,也就是說,我們輸入了make wandboard_config之后,就執行了mkconfig。
??? mkconfig里面其實就是根據輸入的板子的型號,這里是wandboard,調用boards.cfg文件,將arch cpu soc vender board等信息全部讀出來,然后解析這些信息,進行通用頭文件和庫文件的自動配置,比如arm平臺,很多lib庫和頭文件都是可以共用的。就在這一步生成頭文件和很多宏,并將我們的板子的宏配置進去,如下所示為boards.cfg和Imx6平臺相關的內容:
boards.cfg文件與imx6相關配置?展開原碼
expand source?
| cat << EOF >> config.h #define CONFIG_BOARDDIR board/$BOARDDIR #include <config_cmd_defaults.h> #include <config_defaults.h> #include <configs/${CONFIG_NAME}.h> #include <asm/config.h> #include <config_fallbacks.h> #include <config_uncmd_spl.h> |
?
?? 這里調用了boards.cfg文件,切進去查看該文件,這個文件里面其實定義了u-boot可以支持的所有開發板,如下圖:
2.3分析建立軟連接過程
mkconfig建立軟連接?展開原碼
expand source?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | if?[?"$SRCTREE"?!=?"$OBJTREE"?] ; then? mkdir -p ${OBJTREE}/include? mkdir -p ${OBJTREE}/include2? cd ${OBJTREE}/include2? rm -f asm? ln -s ${SRCTREE}/arch/${arch}/include/asm asm? LNPREFIX=${SRCTREE}/arch/${arch}/include/asm/? cd ../include? mkdir -p asm else cd ./include? rm -f asm? ln -s ../arch/${arch}/include/asm asm fi rm -f asm/arch if?[ -z?"${soc}"?] ; then? ln -s ${LNPREFIX}arch-${cpu} asm/arch else ln -s ${LNPREFIX}arch-${soc} asm/arch fi if?[?"${arch}"?=?"arm"?] ; then? rm -f asm/proc? ln -s ${LNPREFIX}proc-armv asm/proc fi |
?
??? 以上是建立軟連接的過程,if [ "$SRCTREE" != "$OBJTREE" ] ; then? 表示判斷源碼目錄是不是我們目標文件生產的目錄,顯然是的,我們生成的目標文件是在u-boot源碼目錄下的,所以直接跳到else后面,執行下面的語句:
??? cd ./include
??? rm -f asm
??? ln -s ../arch/${arch}/include/asm asm
??? 切換到源碼目錄的include目錄下,刪除asm軟連接,然后將上一級目錄下arch/arm/include/asm目錄鏈接到這個目錄來,這是建立了第一個軟連接。可以看得到:
??? 接著rm -f asm/arch刪除asm目錄下的arch軟連接,下面的代碼:
建立軟連接2
?
| 1 2 3 4 5 6 7 8 9 | if?[ -z?"${soc}"?] ; then? ln -s ${LNPREFIX}arch-${cpu} asm/arch else ln -s ${LNPREFIX}arch-${soc} asm/arch fi if?[?"${arch}"?=?"arm"?] ; then rm -f asm/proc? ln -s ${LNPREFIX}proc-armv asm/proc fi |
?
??? 首先判斷soc是否為空,這里soc顯然不為空,執行ln -s ${LNPREFIX}arch-${soc} asm/arch ,這里LNPREFIX為空,所以這句其實就是ln -s ./arch-mx6 asm/arch,下面的同樣是將arm相關的proc鏈接進去。
結果可以通過ls -l來查看:
2.4生成config.mk和頭文件
生成config.mk文件
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ( echo?"ARCH?? = ${arch}"?? if?[ ! -z?"$spl_cpu"?] ; then? echo?'ifeq ($(CONFIG_SPL_BUILD),y)' echo?"CPU??? = ${spl_cpu}" echo?"else" echo?"CPU??? = ${cpu}" echo?"endif"??? else echo?"CPU??? = ${cpu}"??? fi???? echo?"BOARD? = ${board}" ????[?"${vendor}"?] && echo?"VENDOR = ${vendor}"?? [?"${soc}"????] && echo?"SOC??? = ${soc}"?? exit?0 ) > config.mk |
?
???? 上面的代碼其實就是判斷有沒有定義spl_cpu如果定義了那就將spl_cpu信息輸出到CPU,這里沒有定義,因此依次就是確定了CPU.BOARD.SOC這些信息,最后一句> config.mk將以上信息輸出到config.mk后退出。可以切換到./include/目錄下,看到一個config.mk文件,打開看到如下內容:
??? 接著mkconfig文件還做了自動生成頭文件的工作,這部分代碼如下:
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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 for?i in ${TARGETS} ;?do i="`echo ${i} | sed '/=/ {s/=/ /;q; } ; { s/$/ 1/; }'`" echo?"#define CONFIG_${i}"?>>config.h ; done echo?"#define CONFIG_SYS_ARCH? \"${arch}\""??>> config.h echo?"#define CONFIG_SYS_CPU?? \"${cpu}\""???>> config.h echo?"#define CONFIG_SYS_BOARD \"${board}\""?>> config.h [?"${vendor}"?] && echo?"#define CONFIG_SYS_VENDOR \"${vendor}\""?>> config.h [?"${soc}"????] && echo?"#define CONFIG_SYS_SOC??? \"${soc}\""????>> config.h cat << EOF >> config.h #define CONFIG_BOARDDIR board/$BOARDDIR #include <config_cmd_defaults.h> #include <config_defaults.h> #include <configs/${CONFIG_NAME}.h> #include <asm/config.h> #include <config_fallbacks.h> #include <config_uncmd_spl.h> EOF exit?0 |
?
??? 首先檢查config.h存在否,如果不存在就建立一個config,h,然后依次定義宏到config.h中,最后加入一些arm平臺下通用的頭文件,最后保存退出。打開config.h文件,可以清晰看到如下內容:
??? 這里并未定義文件里面的前四行內容,應該是手動添加進去的,確定mxl是否是有SPL啟動,具體是哪個型號,然后根據具體型號再做一個配置,這里寫到imx6image.cfg文件里查看。
imx6img.cfg
?
| 1 2 3 4 5 6 7 8 9 | /* image version */ IMAGE_VERSION 2 /*? * Boot Device : one of? * spi, sd (the board has no nand neither onenand)? */ BOOT_FROM????? sd #define __ASSEMBLY__ #include <config.h> #include "asm/arch/iomux.h" #include "asm/arch/crm_regs.h" #include "clocks.cfg" |
?
這個文件加入了另外幾個頭文件,猜測這個文件是和啟動方式有關的配置文件,這里又加入了clocks.cfg文件,配置了啟動時候的時鐘,這部分代碼后面分析啟動過程的時候再分析。
2.5編譯
??? 這部分代碼比較多,但是主要完成了以下幾個剩余的工作:
??? 1.u-boot版本號確認及語言環境確認
??? 2.解析make后面傳入的參數,例如make -v=1之類的,這里我們沒有
??? 3.指定源碼目錄和目標目錄
??? 4.獲取machine號
??? 5.確定交叉編譯工具鏈,制定了我們的shell名稱:/bin/bash,編譯器套件名稱:gcc,以及一些編譯參數,-Wall表示要提示所有的warning。
??? 6.設置頭文件包含路徑,輸出目標制定目錄,添加平臺相關的頭文件到指定目錄。
??? 7.根據配置執行make以及depend的依賴關系分別調用各子目錄,生成所有的obj文件。
??? 8.交代了u-boot是如何組裝起來的,組裝規則是u-boot.lds這個文件,把start.o和各個子目錄makefile生成的庫文件按照LDFLAGS連接在一起,生成ELF文件u-boot 和連接時內存分配圖文件u-boot.map。這里,我們的u-boot.bin文件我理解的是從u-boot.elf拷貝過來的。
3.u-boot.lds
??? u-boot的代碼是根據u-boot.lds組裝起來的,由于u-boot.lds的代碼比較晦澀,不過不要緊,只要能找到每一個階段的入口就可以了,該文件內容如下:
第一啟動階段代碼入口
?
| 1 2 3 4 5 6 7 8 9 10 11 12 | OUTPUT_FORMAT("elf32-littlearm",?"elf32-littlearm",?"elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { ??. = 0x00000000; ??. = ALIGN(4); .text :? {? *(.__image_copy_start)???//這里指定了影響文件復制的起始地址 arch/arm/cpu/armv7/start.o (.text*)??//指明了啟動第一階段的文件為制定目錄下的start.s *(.text*)? } |
?
??? 下面開始分析start.s和具體上電后的操作。
4.啟動分析
start.S
?
| 22 23 | .globl _start _start: b reset |
?
??? 這里聲明一個連接入口_start,上電后或者復位后第一句就跳轉到reset,切過去:
start.S
?
| 110 111 112 113 114 115 116 117 118 | reset:? bl save_boot_params??? mrs r0, cpsr??//將當前狀態寄存器的值讀到r0 and r1, r0, #0x1f?//將r0的低五位狀態賦值r1,也就是cpsr的低五位狀態 teq r1, #0x1a??//比較CPSR的低五位狀態是否等于0x1a,該狀態說明對應HYP模式,一種非安全狀態行運行的新模式。 bicne r0, r0, #0x1f?//如果不等于那就清楚低五位? orrne r0, r0, #0x13?//同樣設置低五位為0x13,也就是10011,對應的是ARM的SVC管理模式 orr r0, r0, #0xc0??//11000000,禁止IRQ和FIQ msr cpsr,r0//將r0的值讀到CPSR,這時候am誰svc模式,中斷被禁止。 |
?
????
?????????????????????????????????????????????????????????????? CPSR寄存器
???? 這里先跳轉到save_boot_params,bl跳轉后會返回回來繼續執行,還是切過去看save_boot_params做了什么。
save_boot_params
?
| 179 180 181 182 | ENTRY(save_boot_params)? bx lr?? @ back to my caller ENDPROC(save_boot_params)? .weak save_boot_params |
?
??? 這里bx lr就直接返回跳轉來之前的地址,也就是什么都不做,下面的.weak關鍵字作用是如果其他地方定義了save_boot_params那就調用,如果沒有定義,這就是個空函數。
??? 接著上面的代碼段,具體做了什么已經注釋的比較清楚了,接下來:
start.S
?
| 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))? /* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */ mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTRL Register? bic r0, #CR_V? @ V = 0 mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTRL Register /* Set vector address in CP15 VBAR register */ ldr r0, =_start? mcr p15, 0, r0, c12, c0, 0 @Set VBAR #endif #ifndef CONFIG_SKIP_LOWLEVEL_INIT? bl cpu_init_cp15? bl cpu_init_crit #endif bl _main |
?
???? 這里我們沒有定義CONFIG_OMAP44XX和CONFIG_SPL_BUILD,因此執行
??? mrc p15, 0, r0, c1, c0, 0,這是協處理器操作,只有mrc和mcr才能對arm的協處理器進行操作:
????????? MRC {條件}協處理器編碼,協處理器操作碼1,目的寄存器,源寄存器1,源寄存器2,{協處理器操作碼2}
????????? MCR {條件}協處理器編碼,協處理器操作碼1,源寄存器,目的寄存器1,目的寄存器2,{協處理器操作碼2}
??? 這兩個指令一般是成對使用,讀出來在寫進去,設置CP15協處理器的C1寄存器V位為0,查看寄存器手冊:
?? 設置地段一場中斷向量0x0~0x1c。
??? 然后將_start的地址給r0,再將該地址寫到c12寄存器,也就是設置異常向量的基地址:
???
??? 緊接著,這里沒有定義skip_lowlevel_init,跳入cpu_init_cp15 ,顧名思義還是對cp15協處理器的設置。代碼如下:
cpu_init_cp15?展開原碼
expand source?
| 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | ENTRY(cpu_init_cp15) /*? * Invalidate L1 I/D? * 使無效整個數據和指令TLB,然后使無效整個指令cache,清空整個跳轉目標的cache,清空預取緩沖區,清空寫緩沖區??? */ mov r0, #0?? @ set up?for?MCR? mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs? mcr p15, 0, r0, c7, c5, 0 @ invalidate icache? mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array? mcr p15, 0, r0, c7, c10, 4 @ DSB? mcr p15, 0, r0, c7, c5, 4 @ ISB /* * disable MMU stuff and caches?? * 設置低端異常中斷向量,禁止MMU,禁止地址對齊檢查,禁止數據Cache,前面已經禁止了指令cache。緊接著使能地址對齊檢查,使能跳轉預測功能??? */ mrc p15, 0, r0, c1, c0, 0? bic r0, r0, #0x00002000 @ clear bits 13 (--V-)? bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)? orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align? orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB #ifdef CONFIG_SYS_ICACHE_OFF? bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache #else? orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache?//這里沒有定義ICACHE_OFF,因此這里使能指令Cache #endif? mcr p15, 0, r0, c1, c0, 0 #ifdef CONFIG_ARM_ERRATA_716044?? //沒有定義該號碼的宏,跳過 mrc p15, 0, r0, c1, c0, 0 @ read?system?control?register orr r0, r0, #1 << 11 @ set bit #11? mcr p15, 0, r0, c1, c0, 0 @ write?system?control?register #endif /* * 這里是對CP15的C15寄存器進行了操作,這里叫做診斷寄存器,然后將4,6,15都置位,這里我沒找到c15寄存器的手冊說明。 */ #ifdef CONFIG_ARM_ERRATA_742230? mrc p15, 0, r0, c15, c0, 1 @ read diagnostic?register orr r0, r0, #1 << 4? @ set bit #4? mcr p15, 0, r0, c15, c0, 1 @ write diagnostic?register #endif #ifdef CONFIG_ARM_ERRATA_743622? mrc p15, 0, r0, c15, c0, 1 @ read diagnostic?register orr r0, r0, #1 << 6? @ set bit #6? mcr p15, 0, r0, c15, c0, 1 @ write diagnostic?register #endif #ifdef CONFIG_ARM_ERRATA_751472? mrc p15, 0, r0, c15, c0, 1 @ read diagnostic?register orr r0, r0, #1 << 11 @ set bit #11? mcr p15, 0, r0, c15, c0, 1 @ write diagnostic?register #endif mov pc, lr?? @ back to my caller ENDPROC(cpu_init_cp15) |
?
??? 這部分首先對r0清零,然后使無效整個數據和指令TLB,然后使無效整個指令cache,清空整個跳轉目標的cache,清空預取緩沖區,清空寫緩沖區, 設置低端異常中斷向量,禁止MMU,禁止地址對齊檢查,禁止數據Cache,前面已經禁止了指令cache。緊接著使能地址對齊檢查,使能跳轉預測功能 。然后后面有三個勘誤宏,這里定義了三個,分別作了以下事情:對CP15的C15寄存器進行了操作,這里叫做診斷寄存器,然后將4,6,15都置位,這里我沒找到c15寄存器的手冊說明,具體意義不明,不過應該不影響后面的啟動過程。
??? 具體CP15的C0到C15寄存器信息參考下面的鏈接。
????http://blog.sina.com.cn/s/blog_858820890102v1gc.html
??? 完了之后,跳回子函數,然后順序執行到函數cpu_init_crit:
cpu_init_crit?展開原碼
expand source?
| 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | #ifndef CONFIG_SKIP_LOWLEVEL_INIT /*************************************************************************? * * CPU_init_critical registers? *? * setup important registers? * setup memory timing? * *************************************************************************/ ENTRY(cpu_init_crit)? /*?? * Jump to board specific initialization...?? * The Mask ROM will have already initialized?? * basic memory. Go here to bump up clock rate and handle?? * wake up conditions.?? */ ???b lowlevel_init? @ go setup pll,mux,memory ENDPROC(cpu_init_crit) #endif |
?
???? 未定義SKIP_LOWLEVEL_INIT這部分代碼其實就是跳轉到lowlevel_init去了,lowlevel_init的作用就是引導加載c函數做進一步的初始化,切過去。
low_level_init.S
?
| 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ENTRY(lowlevel_init)? /*?? * Setup a temporary stack?? */ ldr sp, =CONFIG_SYS_INIT_SP_ADDR? bic sp, sp, #7?/* 8-byte alignment for ABI compliance */ #ifdef CONFIG_SPL_BUILD? ldr r9, =gdata #else? sub sp, #GD_SIZE? bic sp, sp, #7? mov r9, sp #endif? /*?? * Save the old lr(passed in ip) and the current lr to stack?? */ push {ip, lr} /*?? * go setup pll, mux, memory?? */ bl s_init? pop {ip, pc} ENDPROC(lowlevel_init) |
?
??? 這里首先設置了一個臨時的堆空間,將CONFIG_SYS_INIT_SP_ADDR的地址送到SP,這個地址=(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET),CONFIG_SYS_INIT_RAM_ADDR 在
imx-regs.h里面定義了0x00900000,后面的CONFIG_SYS_INIT_SP_OFFSET未找到,忽略。
??? 設置SP八個字節對齊之后,這里定義了CONFIG_SPL_BUILD。將gdata賦值給r9,跳轉到s_init函數中去。
??? s_init在arch\arm\cpu\armv7\mx6的soc.c中,s_init主要是對IMX6的PFDs進行了板級設置。
??? 在調用結束s_init之后,程序跳轉到到_main函數里面,搜索定位該感受在arch/arm/lib/crt0.S下,這里是main函數的入口,主要做了以下工作:
- 重新對SP賦值, 確認sp是8字對齊
- 在棧頂保留一個global_data的大小, 這個global_data是uboot里面的一個全局數據, 很多地方都會用到. 俗稱 gd_t
- 確認更新后的sp是8字對齊
- r9指向global_data, 后面別的地方想用global_data時候, 可以直接從r9里面獲取地址.
- r0賦值0
- bl?board_init_f: 跳轉到board_init_f. 在編譯SPL時, 分析Makefile可以看出, 該函數的實現是在<arch/arm/lib/spl.c>.
??? board_init_f在arch/arm/lib/spl.c中,主要做了以下事情:
- 對BSS段進行清零操作
- gd = &gdata;
- gd的定義在DECLARE_GLOBAL_DATA_PTR <arch/arm/include/asm/global_data.h>
- #define DECLARE_GLOBAL_DATA_PTR???? register volatile gd_t *gd asm ("r9")
- r9之前初始化了
- #define DECLARE_GLOBAL_DATA_PTR???? register volatile gd_t *gd asm ("r9")
- gdata的定義在本文件中: gd_t gdata __attribute__ ((section(".data")));?
- 它是一個 gd_t 也就是global_data類型的變量
- __attribute__表示這個變量會被放到".data"這個輸入段中. 連接器會把輸入段按照鏈接腳本(u-boot-spl.lds)里面指定的規則存放到輸出段
- gd的定義在DECLARE_GLOBAL_DATA_PTR <arch/arm/include/asm/global_data.h>
??? 接著跳轉到board_init_r,在common/spl/spl.c下面,主要做了以下事情:
??? 對memory,timer初始化,選擇在什么介質啟動,最后判斷image的類型,是u-boot還是linux。
5.總結
????(reset) <arch/arm/cpu/armv7/start.S-> (b lowlevel_init: arch/arm/cpu/armv7/lowlevel_init.S) (b _main) --> <arch/arm/lib/crt0.S> (bl board_init_f) --> <arch/arm/lib/spl.c> (board_init_r) --> <common/spl/spl.c> (jump_to_image_no_args去啟動u-boot)
總結
以上是生活随笔為你收集整理的imx6ul:uboot-2013.10启动过程解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spoken English(001)
- 下一篇: DEDECMS 5.6整合Discuz_