小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

基于ar9331 mips架構(gòu)AP121 uboot分析(3) 啟動流程 | Imagination中文技術(shù)社區(qū)

 云將東游 2016-02-24

mips架構(gòu)u-boot啟動流程

u-boot的啟動過程大致做如下工作:

1、cpu初始化

2、時鐘、串口、內(nèi)存(ddr ram)初始化

3、內(nèi)存劃分、分配棧、數(shù)據(jù)、配置參數(shù)、以及u-boot代碼在內(nèi)存中的位置。

4、對u-boot代碼作relocate

5、初始化malloc、flash、pci以及外設(shè)(比如,網(wǎng)口)

6、進(jìn)入命令行或者直接啟動Linux kernel

整個啟動中要涉及到四個文件:

start_bootstrap.S à cpu/mips/start_bootstrap.S

Lowlevel_init.S à board/ar7240/common/lowlevel_init.S

Cache.S à cpu/mips/cache.S

Board.c à lib_mips/board.c

整個啟動過程分為兩個階段來看:

Stage1:系統(tǒng)上電后執(zhí)行匯編代碼

Stage2:通過一些列設(shè)置搭建了C環(huán)境,通過匯編指令跳轉(zhuǎn)到C語言執(zhí)行.

Stage1:

程序從cpu/mips/start_bootstrap.S的_start_bootstrap開始執(zhí)行.(至于為什么,參考u-boot.lds分析.doc)

先查看start_bootstrap.S文件吧!~

從_start_bootstrap標(biāo)記開始會看到一長串莫名奇妙的代碼:

RVECENT(reset,0) /* U-boot entry point */ /*U-Boot開始執(zhí)行的代碼起始地址*/

RVECENT(reset,1) /* software reboot */ /*軟重啟時U-Boot開始執(zhí)行的起始地址*/

RVECENT(romReserved,2) /*保留本代碼所在的地址,重新映射調(diào)試異常向量時可以使用該空間*/

RVECENT(romReserved,3)

RVECENT(romReserved,4)

RVECENT(romReserved,5)

RVECENT(romReserved,6)

RVECENT(romReserved,7)

RVECENT(romReserved,8)

RVECENT(romReserved,9)

回過頭看剛開始的定義有這樣的代碼:

可以找到:

#defineRVECENT(f,n) \

b f; nop

原來這只是一個簡單的跳轉(zhuǎn)指令,f為一個標(biāo)記,b為跳轉(zhuǎn)指令。

然后看最后,發(fā)現(xiàn):

romReserved:

b romReserved

romExcHandle:

b romExcHandle

這兩個標(biāo)記都構(gòu)建了無意義的死循環(huán)。

通過_start標(biāo)記處的語句RVECENT(reset,0) 代碼跳轉(zhuǎn)到標(biāo)記reset的地方,該段代碼的操作就是對寄存器的清零操作了。Mfc0和mtc0指令是對寄存器的一些讀寫.

Mips 寄存器:http://blog.csdn.net/flyingqr/article/details/7073088

在接下來是對協(xié)處理器的操作了,其中包括:

CP0_WATCHLO,

CP0_WATCHHI,

CP0_STATUS

CP0_CAUSE,

CP0_COUNT,

CP0_COMPARE

CP0_CONFIG

之后,配置寄存器CP0_STATUS,設(shè)置所使用的協(xié)處理器,中斷以及cpu運(yùn)行級別(核心級)。

配置gp寄存器,把GOT段的地址賦給gp寄存器。(gp寄存器的用處會在后面relocate code部分詳細(xì)解釋)

下面就是do_reset:

// load reset register0x1806001c

// bit24, fullchip reset

接下來執(zhí)行/u-boot/board/ar7240/common/lowlevle_init.S的lowlevel_init(la t9, lowlevel_init)函數(shù),主要目的是工作頻率配置,比如wlan-reset,HORNET_BOOTSTRAP_STATUS,RTCreset, AHB/APH reset ,MAC reset ,AR7240_CPU_CLOCK_CONTROL ,DDR工作頻率,等,

/******************************************************************************

* first level initialization:

*

* 0) If clock cntrl reset switch is alreadyset, we're recovering from

* "divider reset"; goto 3.

* 1) Setup divide ratios.

* 2) Reset.

* 3) Setup pll's, wait for lock.

*

*****************************************************************************/

轉(zhuǎn)到了/board/ap7240/ap121/hornet_pll_init.S中執(zhí)行:

hornet_pll_init:

先wlan reset:

set_reg(0xb806001c,0x00c06b30) //1100_0000_0110_1011_0011_0000

nop

set_reg(0xb806001c,0x00c06330) //1100_0000_0110_0011_0011_0000

接著設(shè)置0x180600AC的第2bit(spi啟動),檢查check_val,設(shè)置0x180600AC的值為

set_reg(HORNET_BOOTSTRAP_STATUS,0x0002110e) //0010_0001_0001_0000_1110

RTCreset:

set_reg(0x1810704c, 0x00000003) // 0x1810704c :RTC_FORCE_WAKE

set_reg(0x18107040, 0x00000000) // 0x18107040: RTC_RESET

set_reg(0x18107040, 0x00000001)

wait_loop1:

li t6, KSEG1ADDR(0x18107044) //0x18107044:RTC_STATUS

lw t7, 0(t6)

li t8, 0x2 // 看第1bit是否為1,RTC in on state

and t7, t7, t8

bne t8, t7,wait_loop1

nop

/*AHB/APH reset */

set_reg(0x18104000,0x00000003) TODO:寫3的意思

set_reg(0x18104000, 0x00000000) // 0x18104000:HOST_INTF_RESET_CONTROL

/* MACreset */

set_reg(0x18107000,0x0000000F)

TODO:RTC registers occupy the offset range 0x18107000–0x18107FFC in the AR9331 addressspace.

set_reg(0x18107000, 0x00000000)

接下來有2個

otp_loop0: TODO

otp_loop1: TODO

fetch_otp: TODO

然后有:

*Program PMU */ TODO

/*Program ki, kd */

/*Program phase shift */

先對PLL設(shè)置了:PLLControl Registers 0x18050000-0x18050044 ap121.h 中解釋比較明確

* PLL = (25 MHz * DIV_INT) / (2 ^ OUTDIV) (25 MHz * 32/2 = 400 MHz)

// DIV_INT =32 (25 MHz * 32/2 = 400 MHz)

// REFDIV =1

//RANGE = 0

//OUTDIV = 1

* CPU = PLL / CPU_POST_DIV

* DDR = PLL / DDR_POST_DIV

* AHB = PLL / AHB_POST_DIV

1./* setPLL bypass(Bit 2), CPU_POST_DIV, DDR_POST_DIV, AHB_POST_DIV inCPU clock control */

set_reg(AR7240_CPU_CLOCK_CONTROL,CPU_CLK_CONTROL_VAL1)

#if(CFG_PLL_FREQ == CFG_PLL_400_400_200)

#define CFG_HZ (400000000/2)

// CPU_DIV = 1, RAM_DIV = 1, AHB_DIV = 2

#define CPU_CLK_CONTROL_VAL1 0x00018004 // 1_1000--_0000_0000_0100

#define CPU_CLK_CONTROL_VAL2 0x00008000// 1000_0000_0000_0000

2. /* setSETTLE_TIME in CPU PLL */

set_reg(AR7240_USB_PLL_CONFIG,CPU_PLL_SETTLE_TIME_VAL)

#defineCPU_PLL_SETTLE_TIME_VAL 0x00000352

3. /* set nint, frac, refdiv, outdiv, rangein CPU PLL configuration resiter */

set_reg(AR7240_CPU_PLL_CONFIG,CPU_PLL_CONFIG_VAL1)

#define CPU_PLL_CONFIG_VAL10x40818000//100_0000_1000_0001_1000_0000_0000_0000

#defineCPU_PLL_CONFIG_VAL2 0x00818000// 1000_0001_1000_0000_0000_0000

//DIV_INT = 32

//REFDIV = 1

// RANGE = 0

//OUTDIV = 1

4.讀取AR7240_CPU_PLL_CONFIG第31bit –》PLLupdate :1 ,pending 0,complete

5./* putfrac bit19:10 configuration */

set_reg(AR7240_PCIE_PLL_CONFIG,CPU_PLL_DITHER_FRAC_VAL)

6. /* clear PLL bypass(Bit 2), CPU_POST_DIV,DDR_POST_DIV, AHB_POST_DIV in CPU clock control */

set_reg(AR7240_CPU_CLOCK_CONTROL,CPU_CLK_CONTROL_VAL2)

7. /*Sync mode , Set Bit 8 of DDR Tap Conrtol 3 register */set_reg(AR7240_DDR_TAP_CONTROL3, 0x10105);

TODO:沒有的

下面是/u-boot/cpu/mips/ar7240/hornet_ddr_init.S中的hornet_ddr_init,反正就是初始化ddr(ddr2)

然后執(zhí)行/u-boot/cpu/mips/cache.S中的simple_mips_cache_reset (la t9, simple_mips_cache_reset)對cache進(jìn)行初始化。

接著調(diào)用mips_cache_lock(la t9, mips_cache_lock)

(這個調(diào)用的目的:當(dāng)代碼執(zhí)行到這個時候,ddr ram還沒有配置好,而如果直接調(diào)用C語言的函數(shù)必須完成棧的設(shè)置,而棧必定要在ram中。所以,只有先把一部分cache拿來當(dāng)做ram用。做法就是把一部分cache配置為棧的地址,鎖定。這樣,當(dāng)讀寫棧的內(nèi)存空間時,只會訪問cache,而不會訪問真的ram地址了。)

接著有:mips_cache_lock_24k

這時,配置棧的地址,進(jìn)行調(diào)用函數(shù)bootstrap_board_init_f(/lib_bootstrap/bootstrap_board.c)進(jìn)入函數(shù)board_init_f(la t9, board_init_f)后,首先做一些列的初始化:

Timer_init 時鐘初始化

Serial_init 串口初始化

Init_func_ram 初始化內(nèi)存,配置ddr controller

這一系列工作完成后,串口和內(nèi)存都已經(jīng)可以用了。

然后,就要把內(nèi)存進(jìn)行劃分,在內(nèi)存的最后一部分,留出u-boot代碼大小的空間,準(zhǔn)備把u-boot代碼從flash搬移到這里。

然后,是堆的空間,malloc的內(nèi)存就來自于這里。

緊接著放兩個全局?jǐn)?shù)據(jù)結(jié)構(gòu)bd_infoglobal_data和環(huán)境變量boot_params。

最后,是棧的空間。

當(dāng)內(nèi)存劃分好后,就準(zhǔn)備進(jìn)行relocate code了。

(relocate code含義:

通常u-boot的執(zhí)行代碼肯定是在flash上(調(diào)試可以在ram上).當(dāng)啟動起來之后,要把它從flash上搬移到ram里運(yùn)行

)

但是,存在的問題是,flash地址和ram地址是不同的。當(dāng)我們把代碼從flash搬移到ram中后,當(dāng)執(zhí)行函數(shù)跳轉(zhuǎn)時,代碼里的函數(shù)地址還是flash的地址,一跳,又重新跳回去了(跳回了flash)。

IPC(position-independentcode) 由此引出了。

原理:

當(dāng)使用IPC方式時,在用gcc編譯時需要加上-fpic的選項(xiàng)。編譯器會為你的可執(zhí)行代碼建立一個GOT(global offset table)的段。一個地址在GOT表中有一項(xiàng),里面存放地址的信息,在使用這個地址時,只要根據(jù)這個地址的編號(也可以叫做偏移量offset)找到表中相應(yīng)的項(xiàng)目,就可以取得那個地址了。

而如果位置發(fā)生變化,只要對GOT 表中的地址進(jìn)行修改就可以了。

例:

Lw t9,1088(gp)

Jalr t9

這里,gp存放的就是GOT表的起始地址,而1088就是要調(diào)用函數(shù)offset,也就說GOT表的那個位置存放著它的地址。Lw t9,1088(gp)把函數(shù)地址放入t9寄存器,然后調(diào)用就可以了。

Relocate code說簡單一點(diǎn)就是:把u-boot的執(zhí)行代碼直接從flash里copy到ram的相應(yīng)區(qū)域。

然后,把GOT表中的地址都加上一個偏移量,這個偏移量就是flash里的地址與ram里的地址差。

這里完成的操作還有一些其他工作,比如:設(shè)置新的棧指針,從flash代碼里跳轉(zhuǎn)到ram代碼里等等.

之后,進(jìn)入board.c的board_init_r函數(shù)。進(jìn)入stage2。

Stage2:

在board_init_r函數(shù)中初始化malloc,flash,pci以及外設(shè)(如:網(wǎng)口),最后進(jìn)入命令行或者直接啟動Linux Kernel.

這樣,u-boot的啟動工作完成。

本文轉(zhuǎn)自:onejacky的專欄

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多