在基于Linux的AM335x軟件開(kāi)發(fā)流程中,第一步就是U-Boot/SPL(SecondProgram Loader)的移植。在移植中遇到問(wèn)題比較常見(jiàn),而U-Boot/SPL的調(diào)試手段比較簡(jiǎn)陋,不便于迅速找到問(wèn)題。利用仿真器可以單步調(diào)試的特點(diǎn),就可以迅速定位到出問(wèn)題的代碼所在位置,加速移植的調(diào)試過(guò)程。本文主要介紹如何用CCS+emulator調(diào)試基于AM335x的U-Boot/SPL。
1. AM335x Linux啟動(dòng)過(guò)程以及U-Boot/SPL調(diào)試代碼的準(zhǔn)備
1.1 [url=]AM335x Linux[/url]的啟動(dòng)過(guò)程
AM335x Linux的啟動(dòng)主要包括ROM,SPL, U-Boot 和kernel四個(gè)啟動(dòng)步驟:
A. ROM code
ROM code是固化在芯片內(nèi)部的代碼,當(dāng)上電時(shí)序正確,而且晶振等芯片啟動(dòng)所需的條件都具備時(shí),AM335x會(huì)從ROM code開(kāi)始運(yùn)行。
ROM code首先會(huì)讀取sys_boot引腳上的配置,以確定存放SPL的存儲(chǔ)器,或者可以獲取SPL的外設(shè)。
具體可以參考AM335x technical reference manual中的第26章 Initialization。
ROM code會(huì)從相應(yīng)的地方讀取/獲取SPL,并運(yùn)行SPL。
B. SPL
SPL 和U-Boot 是bootloader的兩個(gè)階段。這里分為兩個(gè)階段的原因是, ROM code中不會(huì)配置DDR,時(shí)鐘等最小系統(tǒng),所以ROM code只能把bootloader加載到片上SRAM中,而片上SRAM對(duì)成本影響很大,所以通常很小,例如在AM335x上只有64K,不足夠放下整個(gè)U-Boot,所以將U-Boot分成兩部分,SPL和U-Boot。
SPL主要的職責(zé)就是初始化DDR,時(shí)鐘等最小系統(tǒng),以讀取U-Boot,并加載到DDR中。具體來(lái)看,SPL 由ROM code加載到片上SRAM的起始位置,也就是0x402F0400。SPL會(huì)進(jìn)一步對(duì)芯片進(jìn)行配置,主要包括以下幾個(gè)方面以完成其主要職責(zé):
a. 配置ARM core。 主要包括對(duì)中斷向量表,cache,MMU等的配置。
b. 配置時(shí)鐘系統(tǒng),主要是PLL等。這個(gè)是配置各個(gè)功能模塊的基礎(chǔ)。
c. 配置UART,timer等。主要用于輸出必要的調(diào)試信息,或者提供些時(shí)鐘工具。
d. 配置I2C和PMIC。這個(gè)主要是為了配置電源管理芯片。
e. 配置DDR。
f. 配置 U-Boot所在的存儲(chǔ)器或者外設(shè)。
完成配置后,SPL會(huì)讀取U-Boot,并運(yùn)行U-Boot。
C. U-Boot
U-Boot 主要的工作就是正確加載Kernel。和SPL類(lèi)似,U-Boot也是要加載下一個(gè)階段的image,但是U-Boot提供了更多外設(shè)的支持和更多的調(diào)試工具。所以,U-Boot也要進(jìn)行各個(gè)模塊的配置,上述SPL配置的部分, 除了DDR外,U-Boot也會(huì)根據(jù)需求重新配置(這里重置主要是U-Boot是一個(gè)開(kāi)源工程,其要兼容某些特殊的芯片,從而需要做重載)。此外,U- Boot也會(huì)對(duì)網(wǎng)口,SD卡等根據(jù)需求進(jìn)行配置。
U-Boot 和SPL的工作流程比有一點(diǎn)是有較大差異的,就是會(huì)對(duì)自身進(jìn)行一次重載。這個(gè)在后面介紹U-Boot調(diào)試的時(shí)候,會(huì)有具體介紹。
完成配置后,U-Boot 會(huì)從相應(yīng)的存儲(chǔ)器或者外設(shè)讀取Kernel,并傳遞參數(shù)給kernel,運(yùn)行kernel。
D. Kernel
Kernel運(yùn)行起來(lái)就代表Linux運(yùn)行起來(lái)了,表明了啟動(dòng)過(guò)程的結(jié)束。
1.2 U-Boot/SPL 調(diào)試代碼的準(zhǔn)備
1.2.1下載U-Boot/SPL 代碼
U-Boot/SPL的代碼在一個(gè)包里面,通過(guò)編譯宏來(lái)分別編譯。目前TI U-Boot/SPL 代碼發(fā)布主要有兩個(gè)渠道,具體如下
A. 通過(guò)GIT開(kāi)源的方式發(fā)布:
git://arago-project.org/git/projects/U-Boot-am33x.git
可以獲取最新的代碼,包含了最新的bug的修復(fù)。
B. 通過(guò)TI的官網(wǎng)的EZSDK發(fā)布:
http://software-dl.ti.com/dsps/dsps_public_sw/am_bu/sdk/AM335xSDK/latest/index_FDS.html
EZSDK是正式發(fā)布的軟件包,經(jīng)過(guò)全面測(cè)試,性能穩(wěn)定,U-Boot/SPL在board-support 目錄中??梢赃x擇EZSDK作為開(kāi)發(fā)的基礎(chǔ)代碼。當(dāng)有問(wèn)題時(shí), 可到GIT上查找最新的代碼是否有bug fix。
1.2.2 U-Boot/SPL的編譯
為了便于用CCS進(jìn)行調(diào)試, 在編譯上需要注意兩點(diǎn),其一,是要加入調(diào)試信息,就是為了加入symbol等信息;其二,去掉編譯器的性能優(yōu)化編譯選項(xiàng),這個(gè)主要是因?yàn)?,?yōu)化后的代碼執(zhí)行順序相對(duì)C代碼會(huì)有調(diào)整。
針對(duì)這兩點(diǎn),在Uboot/SPL中,需要在config.mk中進(jìn)行修改:
A. 在CFLAG 和 AFLAG中加入調(diào)試編譯選項(xiàng),從而加入調(diào)試信息:
278ALL_AFLAGS = $(AFLAGS) $(AFLAGS_$(BCURDIR)/$(@F)) $(AFLAGS_$(BCURDIR)) –g
279ALL_CFLAGS = $(CFLAGS) $(CFLAGS_$(BCURDIR)/$(@F)) $(CFLAGS_$(BCURDIR)) –g
B. 去掉 CFLAG中的編譯選項(xiàng), -O2(U-Boot中默認(rèn)是-O2)
61 HOSTCFLAGS = -Wall -Wstrict-prototypes -O2-fomit-frame-pointer
編譯過(guò)程可以參考http://processors.wiki.ti.com/index.php/AM335x_U-Boot_User%27s_Guide
1.2.3 可執(zhí)行文件
經(jīng)過(guò)編譯后,就會(huì)生成可執(zhí)行文件,也就是我們通常所說(shuō)的image,這里會(huì)生成的image主要用AM335xLinux啟動(dòng)的兩個(gè)階段,MLO(SPL)和U-Boot。
這里,SPL生成的image在am335/U-Boot-am33x/am335x/spl中,
A. am335/U-Boot-am33x/MLO 負(fù)責(zé)AM335x啟動(dòng)的第一階段。
B. U-Boot-spl 作為帶有調(diào)試信息的image,可以在CCS中用作導(dǎo)入調(diào)試信息。
C. U-Boot-spl.bin 包含有調(diào)試信息,是調(diào)試時(shí)需要的image。
D. U-Boot-spl.map 這個(gè)文件里面存儲(chǔ)了spl的memory map信息,可以找到各函數(shù)入口的地址。
U-Boot生成的image在U-Boot-am33x/am335x中,具體如下:
A. U-Boot.img負(fù)責(zé)AM335x啟動(dòng)的第二階段
B. U-Boot 包含有調(diào)試信息,屬于ELF格式,是調(diào)試時(shí)需要的image。
C. U-Boot.map這個(gè)文件里面存儲(chǔ)了U-Boot的memory map信息,可以找到各函數(shù)入口的地址
調(diào)試環(huán)境主要包含3個(gè)部分,仿真器,集成調(diào)試環(huán)境和開(kāi)發(fā)板。下面將逐一介紹:
2.1 仿真器(emulator)
目前支持AM335x的仿真器的型號(hào)比較多,有XDS560v2,XDS510,XDS100v2, XDS100v3,等,比較常見(jiàn)的是XDS560v2和XDS100v2。
XDS560v2,性能好,速度快,具有trace功能,但是價(jià)格偏貴。 XDS100v2價(jià)格比較便宜。 其具備和XDS560v2一樣的基本調(diào)試功能,只是XDS100v2的速度相對(duì)略慢。
XDS560v2和XDS100v2在PC機(jī)上的驅(qū)動(dòng)(Windows,Linux)都已經(jīng)包含在CCS中了,所以安裝了最新版的CCS,就會(huì)安裝相應(yīng)的驅(qū)動(dòng)。
2.2 集成開(kāi)發(fā)環(huán)境
TI有自己的集成開(kāi)發(fā)環(huán)境(IDE)CCS.目前最新的版本是基于Eclipse IDE架構(gòu)的,界面新穎方便。
下載地址 http://processors.wiki.ti.com/index.php/Download_CCS。
CCS有Windows版本和Linux 版本,后面會(huì)在介紹調(diào)試過(guò)程中具體介紹兩者的差異。
2.3 開(kāi)發(fā)板
目前,針對(duì)不同的應(yīng)用,TI發(fā)布了基于AM335x的多個(gè)開(kāi)發(fā)板。其中BeagleBone,Starter Kit和ICE上配置了基于FT2232的xds100v2。而GPEVM和IDK上引出了CTI JTAG接口。
這里選擇GP EVM和 Spectrum DigitalXDS560v2 作為調(diào)試平臺(tái)。
3. CCS 調(diào)試Uboot/SPL的具體步驟
下面正式開(kāi)始CCS的調(diào)試。調(diào)試的過(guò)程主要分為導(dǎo)入U(xiǎn)-Boot/SPL 工程, CCS 連接AM335x,代碼調(diào)試等幾個(gè)部分。
3.1 導(dǎo)入CCS代碼
在CCS中, Menu File -》 Import … 選擇 Makefile 方式導(dǎo)入,如下圖所示:
在ezsdk中,U-Boot/SPL所對(duì)應(yīng)的Makefile的具體路徑如下:
/home/sitara/ti-sdk-am335x-evm-05.05.00.00/board-support/U-Boot-2011.09-psp04.06.00.08
如前面所提到,U-Boot 和SPL的源碼在同一個(gè)文件夾的,通過(guò)不同的Makefile管理不同的編譯宏來(lái)區(qū)分的。這里導(dǎo)入的是U-Boot的代碼對(duì)應(yīng)的Makefile,會(huì)相應(yīng)的導(dǎo)入U(xiǎn)-Boot對(duì)應(yīng)的預(yù)編譯選項(xiàng),因?yàn)槠浒怂械拇a。而對(duì)于SPL,也會(huì)相應(yīng)的一起帶入,只是在CCS中看到的代碼的宏定義有些不對(duì),但這個(gè)不影響調(diào)試。
3.2 CCS 連接 AM335x.
主要分成仿真器的連接,target連接和Debug配置等幾部分:
3.2.1 [url=]仿真器的連接[/url]
對(duì)于 AM335x GP EVM選用Spectrum DigitalXDS560v2 的20 pin的接口板,連在baseboard的J2口上即可,注意pin腳的順序,不要把JTAG 接口插反了。
對(duì)于beaglebone,StarterKit,ICE等,這些板子已經(jīng)把XDS100v2 仿真器集成到板子上了,所以直接用usb線連到PC機(jī)上即可。
A. CCS的配置
CCS的配置主要包括Target的配置和連接兩部分。
a. Target 配置
Target的配置包含兩個(gè)部分,一個(gè)是仿真器(XDS560v2),另一個(gè)就是SOC(AM335x)。具體操作如下:
i. View -》 Target Configurations
ii. 點(diǎn)右鍵選擇New Target Configuration.
iii. 新建一個(gè)叫做AM335_EVM的target.
iv. Connection中選擇 Spectrum Digital XDS560V2 STM USB Emulator.
v. 對(duì)于XDS100v2 , 可以選擇 Texas InstrumentsXDS100v2 USB Emulator.
vi. 在Board or Device 中選擇AM335x.
vii. 點(diǎn)擊Save 保存。
viii. 點(diǎn)擊Test Connection 看是否能夠正常連接。
配置target成功后,會(huì)看到如下界面
3.2.2 Target 連接
A. 右鍵選中Target Configurations中已配置好的target,AM335x_EVM.ccxml, 在右鍵菜單中選擇Launch SelectedConfiguration,連接成功后,可以得到下圖
此時(shí),PC 和仿真器以及仿真器和SOC的JTAG連接成功,但是ARM core還沒(méi)有連上。從圖中可以看到,有多個(gè)core的配置選項(xiàng),由于U-Boot/SPL,Linux 運(yùn)行在ARM coretex-A8 core上,這里只關(guān)注ARM core。
B. 在Debug窗口中,右鍵點(diǎn)擊CortxA8 core, 選擇Connect Target. 連接成功后,如下圖所示:
此時(shí),已經(jīng)成功連上AM335x的Cortex-A8 core了。
3.2.3 Debug配置
這里的debug配置,是對(duì)emulator連上core后行為的設(shè)置。 可以通過(guò)鼠標(biāo)右鍵點(diǎn)擊properties,得到以下界面:
在該頁(yè)配置中,在調(diào)試過(guò)程需要調(diào)整的就是Auto RunOptions,可以根據(jù)需要設(shè)置,當(dāng)加載了image后,core自動(dòng)運(yùn)行到指定的symbol,并且被JTAG接口所停住
調(diào)試U-Boot/SPL的方式有兩種,主要涉及如何加載image:一種是把image通過(guò)JTAG下載到片上RAM或者DDR中,然后導(dǎo)入 symbol,重置 PC指針到image的入口處,進(jìn)行調(diào)試;另一種,把image燒到SD卡或者其他啟動(dòng)存儲(chǔ)器上,啟動(dòng)板子,通過(guò)JTAG停住core的PC指針,導(dǎo)入 symbol,重置 PC指針到image的入口處,進(jìn)行調(diào)試。
下面會(huì)在具體步驟中說(shuō)明這兩種方式如何操作:
A. 下載SPL image到AM335x中。
如果AM335x是從SD卡方式啟動(dòng),此時(shí) SPL image已經(jīng)被ROM code成功讀到片上 RAM中,就不需要加載 SPLimage了。
如果選擇SPL image通過(guò)CCS下載,鼠標(biāo)左鍵選擇CortxA8core , 然后在CCS菜單中, Tools -》 Load Memory, 選擇編譯好的SPL image U-Boot-spl.bin,如下圖所示:
選擇加載的地址。由于加載的U-Boot-spl.bin是RAW data,所以需要指定loadaddress,這個(gè)地址就是SPL的入口地址
對(duì)于AM335x,SPL的入口地址是0x402F0400,對(duì)應(yīng)的宏定義為CONFIG_SPL_TEXT_BASE, 該宏定義在include/configs/am335x_evm.h中。通過(guò)編譯出的map文件U-Boot-spl.map也可以查到,是 __startsymbol對(duì)應(yīng)的地址。
設(shè)定加載image內(nèi)型。 由于所有的代碼都是運(yùn)行在ARM(32bit)模式下。所以Type-size也要設(shè)成32bit。設(shè)置界面如下:
最后點(diǎn)擊Finish,SPL就會(huì)被load到片上RAM中了。如果在console窗口中有錯(cuò)誤信息,需要把SPL image重新加載 一遍。
B. 加載 symbol。
在上一步里,只是加載了RAW image,還沒(méi)有加載調(diào)試所需要的帶有調(diào)試信息的symbol。
可以通過(guò)Run -》 Load -》 LoadSymbols 加載symbol信息,界面如下:
這里選擇的是帶有symbol信息的U-Boot-spl.
C. 設(shè)置Cortex-A8 core到ARM狀態(tài)。
ARM core 啟動(dòng)后,默認(rèn)在Thumb(16bit)模式下,如前面所說(shuō),需要將其切換到ARM(32bit)下。具體做法是,View-》Registers, 展開(kāi)CPSR寄存器,把T位設(shè)置為0。界面如下:
D. SPL的單步調(diào)試。
a. 從SPL編譯的memory map可知,SPL從0x402f0400開(kāi)始執(zhí)行,所以首先就要把寄存器PC的值設(shè)為0x402f0400??梢酝ㄟ^(guò) View-》Registers中設(shè)置PC指針的值即可, 界面如下,將紅色框里面的改為0x402f0400即可。
b. 點(diǎn)擊Debug窗口(view-》debug)上tool bar中的匯編單步按鈕,如下圖所示,就開(kāi)始調(diào)試了。
這時(shí),在反匯編窗口(view-》disassembly)中,如下圖所示,看到的是匯編代碼,而且在編輯窗口這邊看不到源碼。這是由于開(kāi)始執(zhí)行的代碼在/arch/arm/cpu/armv7/start.s 中,反匯編和匯編一樣,所以沒(méi)有顯示源碼。
同時(shí),可以看到PC指針運(yùn)行到0x402f0458處。這里只是單步執(zhí)行了一條指令,為什么跳過(guò)了這么大塊地址?這里的單步運(yùn)行,指令地址空間跳轉(zhuǎn)了n指令,而不是一條指令,這是因?yàn)?x402f0400處存放的是異常中斷向量表,通過(guò)默認(rèn)啟動(dòng)的入口跳到reset symbol對(duì)應(yīng)的地址了,也就是在0x402f0400處跳轉(zhuǎn)到0x402f0458了,具體代碼(arch/arm/cpu/armv7 /start.S)如下:
_start: b reset
reset:
bl save_boot_params
接下來(lái),可以在C代碼中設(shè)置斷點(diǎn),進(jìn)行調(diào)試了。有兩點(diǎn)值得注意:
i. 如果編譯的時(shí)候,交叉編譯器的性能優(yōu)化選項(xiàng)是開(kāi)著的,那么優(yōu)化后編譯生成的代碼,其執(zhí)行循序和C源碼有差別,這時(shí)設(shè)置斷點(diǎn)時(shí),其實(shí)際的位置不會(huì)很準(zhǔn)。所以,這里可以根據(jù)需要,決定是否關(guān)閉-O2選項(xiàng)。
ii. 在CCS中,把core停下來(lái)時(shí),CCS會(huì)根據(jù)image中調(diào)試信息所包含的源碼路徑,找到對(duì)應(yīng)的源碼和symbol。由于U-Boot/SPL是在 Linux中編譯,所以其路徑都是Linux下的路徑,所以Linux版本的CCS可以直接找到對(duì)應(yīng)的源碼,而對(duì)于Windows版本的CCS不能直接找到,需要通過(guò)手動(dòng)找到源碼,但是找到一個(gè)文件的源碼后,CCS會(huì)根據(jù)相對(duì)路徑找到其他文件。除了這點(diǎn)外,Linux和Windows的CCS配置使用是一樣的。
3.4 U-Boot的調(diào)試
總體來(lái)說(shuō), U-Boot的調(diào)試過(guò)程和SPL調(diào)試過(guò)程是類(lèi)似的,這里主要說(shuō)明不同的幾點(diǎn):
A. 從AM335x的啟動(dòng)過(guò)程可知,U-Boot是運(yùn)行在DDR中的,而DDR是由SPL來(lái)初始化的,所以,加載U-Boot前,先加載并運(yùn)行SPL。
B. 加載U-Boot 的image是 U-Boot。 這里U-Boot 是ELF格式的, 其包含了加載地址, symbol等信息,所以使用CCS 菜單 Run-》 Load-》 LoadProgram, 加載U-Boot 即可。加載成功后, 如下圖所示:
如圖所示, PC直接指到0x80100000地址了,也就是U-Boot的起始地址(入口)了,該地址是CCS從頭ELF頭里面得到的,其定義在CONFIG_SYS_TEXT_BASE(include/configs/am335x_evm.h)中。
C. 相對(duì) SPL 的調(diào)試, U-Boot有個(gè)地方不同,即有代碼的重載(code relocation), 重載后代碼的在SOC上的memory map和編譯出的memory map會(huì)有個(gè)偏移。這個(gè)過(guò)程是在函數(shù)relocate_code()中完成的。 relocate_code()函數(shù)是在board_init_f()中調(diào)用的,如果需要調(diào)試從調(diào)用該函數(shù)開(kāi)始后面的代碼,則加上偏移重載symbol。
在CCS的菜單, Run-》 Load -》 Add Symbols, 加載的image還是前面的U-Boot, data/code offset 都是0x9FF88000。 這里的offset是從gd-》relocaddr(arch/arm arch/arm/lib/board.c)得到的。設(shè)置界面如下:
注意到上述幾點(diǎn),然后就可以按照SPL的調(diào)試過(guò)程對(duì)U-Boot進(jìn)行調(diào)試了。
4. 總結(jié)
關(guān)于用CCS+emulator對(duì)AM335x的U-Boot/SPL的調(diào)試就介紹完了。這里介紹的方法,包含了CCS+emulator調(diào)試的基本原則,不僅僅可以運(yùn)用于U-Boot/SPL調(diào)試,也可以運(yùn)用于Starterware,Kernel等調(diào)試。
評(píng)論
查看更多