吳亞杰, 劉衛(wèi)東 ,, 曾小光
(1.中國海洋大學(xué) 信息科學(xué)與工程學(xué)院,山東 青島 266100;2.海信電器股份有限公司 山東 青島 200071)
龍芯是中國科學(xué)院計算所研制的通用CPU,已獲得MIPS科技公司的MIPS指令集的專利授權(quán)。龍芯1號的CPU主頻是266 MHz,最早在2002年開始產(chǎn)業(yè)化應(yīng)用。龍芯2號主頻最高為1 GHz。龍芯3號于2010年推出成品,其設(shè)計的目標(biāo)則在多核心的設(shè)計[1]。隨著龍芯的發(fā)展,龍芯CPU已不僅僅局限于個人桌面計算機(jī)領(lǐng)域,在嵌入式開發(fā)領(lǐng)域,龍芯CPU也同樣發(fā)展迅速,從2000年以來,越來越多的產(chǎn)品開始采用龍芯CPU。在計算機(jī)的體系結(jié)構(gòu)中,無論是個人計算機(jī)、服務(wù)器還是嵌入式領(lǐng)域,基本輸入輸出系統(tǒng)BIOS是必不可少的,因?yàn)锽IOS負(fù)責(zé)計算機(jī)系統(tǒng)的開機(jī)自檢、板級硬件初始化、加載操作系統(tǒng)內(nèi)核以及基本I/O功能。
PMON是一款ROM-Monitor型的開源軟件,最初是為了LSI Logic MIPS R3000評估板的功能需求而開發(fā)的。經(jīng)過多年發(fā)展,目前已經(jīng)能夠支持MIPS、ARM、PPC和X86等CPU體系[2]。PMON具有強(qiáng)大而豐富的功能,除基本的I/O功能外,還包括CPU初始化、板級外設(shè)初始化與檢測、操作系統(tǒng)引導(dǎo)和調(diào)試等功能,并且 PMON支持從Flash、IDE、TFTP以及USB來啟動操作系統(tǒng)。
PMON源代碼的目錄結(jié)構(gòu)如圖1所示,對于圖示中關(guān)鍵模塊說明如下:
圖1 PMON目錄結(jié)構(gòu)Fig.1 PMON composition
1)Targets目錄 Targets目錄下存放的是與板級相關(guān)的代碼,該目錄下的每個子目錄都對應(yīng)著某一個具體的開發(fā)板,當(dāng)要將PMON移植到一個新的開發(fā)板時,就需要在該目錄新建一個子目錄,并向新建的子目錄中添加開發(fā)板相關(guān)的代碼,其中主要有以下幾個重要文件:start.S文件位于Targets/mips_board/mips_board目錄下,是整個PMON運(yùn)行的起點(diǎn);tgt_machdep.c文件位于 Targets/mips_board/mips_board目錄下,完成大部分板級外設(shè)的初始化工作;Targets/mips_board/dev目錄存放板級外設(shè)的驅(qū)動程序,所需移植的網(wǎng)卡驅(qū)動文件即存放于此目錄中;Targets/mips_board/conf目錄主要存放與硬件板相關(guān)的配置文件。大部分的文件都在Targets/mips_board/compile/mips_board目錄中完成編譯,調(diào)試用的pmon.gdb文件即位于此目錄。
2)conf目錄 Conf目錄下存放的是整個PMON系統(tǒng)的配置文件。
3)pmon目錄 該目錄下存放的是PMON公用的代碼,包括PMON所支持的各種命令,與CPU相關(guān)的代碼以及文件系統(tǒng)相關(guān)的代碼,主要有以下幾個子目錄:arch目錄下的子目錄存放的是與CPU相關(guān)的代碼;cmds目錄下存放的是各種在PMON中可以使用的命令文件,比如:ifup、devcp、g等命令,如果要想向PMON中添加新的命令,需要在此目錄下添加源文件、實(shí)現(xiàn)該命令功能即可;fs目錄下存放的是與各文件系統(tǒng)相關(guān)的代碼;common目錄下存放的是一些通用代碼,比如:命令解析、調(diào)試接口、異常處理、環(huán)境變量設(shè)置程序等部分;netio目錄下存放的是與網(wǎng)絡(luò)相關(guān)的命令的實(shí)現(xiàn)代碼。
4)Sys目錄 Sys目錄存放的是系統(tǒng)支持文件。
5)Lib目錄 Lib目錄存放的是庫的實(shí)現(xiàn)代碼。
6)zloader.mips_board目錄 最終燒寫到 Nand Flash中的的gzrom.bin文件就是在該目錄下經(jīng)過鏈接而生成的。
當(dāng)開發(fā)板上電之后,CPU即從0xBFC00000處取指令執(zhí)行,整個PMON的入口位于start.S文件。該匯編程序主要完成CPU的初始化工作,設(shè)置異常向量入口、設(shè)置棧、初始化UART、初始化內(nèi)存、初始化CACHE,并完成對PMON的代碼拷貝工作,即由Nor Flash搬運(yùn)到SDRAM,以提高代碼執(zhí)行速度[3]。最后PC指針跳轉(zhuǎn)到PMON的C入口initmips函數(shù)處繼續(xù)執(zhí)行,從此進(jìn)入C語言的執(zhí)行環(huán)境。整個執(zhí)行流程如圖2所示。
圖2 PMON初始化流程Fig.2 Flow chart of PMON initializing
在initmips函數(shù)中主要通過dbginit這個函數(shù)來完成大部分的初始化工作,主要有以下幾個函數(shù)來實(shí)現(xiàn)初始化工作:
1)__init函數(shù): 初始化帶有 __attribute__ ((constructor))屬性的函數(shù)。
2)envinit函數(shù):環(huán)境變量初始化。
3)init_net函數(shù):網(wǎng)絡(luò)初始化,網(wǎng)卡設(shè)備的部分初始化也在這個函數(shù)中完成。
4)histinit函數(shù):初始化歷史命令記錄。
在initmips函數(shù)完成初始化任務(wù)后,即跳轉(zhuǎn)到pmon/common/main.c中的main函數(shù)執(zhí)行,在main函數(shù)中設(shè)置完一些參數(shù)后,即進(jìn)入一個while循環(huán),等待用戶輸入命令,while循環(huán)內(nèi)部主要有兩個函數(shù)get_line和do_cmd函數(shù)。get_line函數(shù)一直試圖獲取用戶輸入的命令,而do_cmd函數(shù)負(fù)責(zé)解析命令,解析成功后,則分派相應(yīng)的命令函數(shù)去執(zhí)行;解析失敗則返回到while循環(huán),繼續(xù)等待用戶輸入命令。執(zhí)行到這里PMON已經(jīng)完全運(yùn)行起來了。此時如果需要加載內(nèi)核,用load命令將內(nèi)核加載到內(nèi)存中,接著用g命令則傳遞參數(shù)給內(nèi)核,并開始啟動操作系統(tǒng)。
PMON與其他Bootloader相比,其優(yōu)勢在于PMON的調(diào)試功能強(qiáng)大。PMON本身能支持設(shè)置斷點(diǎn)命令b、查看/設(shè)置寄存器命令r、單步執(zhí)行命令t、查看堆棧信息命令bt以及繼續(xù)執(zhí)行命令c等調(diào)試相關(guān)的命令。b命令用于設(shè)置斷點(diǎn),需要注意的是在PMON中最多可以支持32個斷點(diǎn)。r命令用于顯示/設(shè)置CPU寄存器,直接輸入r后會打印所有寄存器的信息。t命令用于單步執(zhí)行。bt命令用于顯示當(dāng)前堆棧信息。c命令用于繼續(xù)執(zhí)行,即從當(dāng)前斷點(diǎn)處繼續(xù)往下執(zhí)行,相當(dāng)于gdb的continue命令。除了上面列出的調(diào)試命令外,PMON還支持很多其它命令,比如:用于燒寫Nor Flash的devcp命令、顯示設(shè)備的devls命令、設(shè)置環(huán)境變量的set命令、顯示環(huán)境變量的env命令、加載文件的load命令、運(yùn)行程序的g命令等。
以上重點(diǎn)描述了PMON的整體執(zhí)行過程,接下來就要具體實(shí)現(xiàn)在PMON中的網(wǎng)卡移植過程。首先要在配置文件Targets/Hiview/conf/file.Hiview中添加如下部分:
上面這部分內(nèi)容定義了網(wǎng)卡掛載的總線,以及需要編譯的網(wǎng)卡驅(qū)動的源代碼文件等,在重新編譯PMON時需要執(zhí)行make cfg這個命令,此時會讀取配置文件,從而生成一個名為cfdata的數(shù)組,在PMON的啟動過程中會通過configure函數(shù)去配置已知的各個設(shè)備,并通過掃描有哪些設(shè)備掛在了總線上,PMON根據(jù)cfdata數(shù)組依次掃描設(shè)備。PMON首先通過config_rootfound函數(shù)來查找根設(shè)備,查找成功后再通過config_rootsearch函數(shù)來查找根設(shè)備上的子設(shè)備,子設(shè)備查找成功后則執(zhí)行相應(yīng)的子設(shè)備的掛載函數(shù),通知PMON該子設(shè)備已找到,并將相應(yīng)的子設(shè)備操作函數(shù)注冊到PMON中。
若網(wǎng)卡設(shè)備查找成功,則執(zhí)行網(wǎng)卡的掛載函數(shù),即fxp_attach函數(shù),在fxp_attach函數(shù)中完成中斷處理函數(shù)fxp_intr的注冊,調(diào)用tgt_poll_register函數(shù)將中斷處理函數(shù)fxp_intr注冊到查詢列表poll_list上。在fxp_attach函數(shù)中完成的另外一個重要工作是將網(wǎng)卡驅(qū)動的函數(shù)添加到PMON中,以便PMON的上層接口能夠正確調(diào)用到網(wǎng)卡設(shè)備的下層驅(qū)動函數(shù)來實(shí)現(xiàn)功能,這里通過填充net_device結(jié)構(gòu)體來實(shí)現(xiàn),如下代碼即實(shí)現(xiàn)了該工作:
其中打開網(wǎng)絡(luò)設(shè)備通過net_fxp_open函數(shù)來完成,net_fxp_open主要工作是初始化網(wǎng)卡設(shè)備的相關(guān)寄存器,并分配用于接收、發(fā)送數(shù)據(jù)的緩沖區(qū),設(shè)置好緩沖區(qū)的狀態(tài)。net_fxp_close函數(shù)則是在關(guān)閉網(wǎng)絡(luò)設(shè)備時調(diào)用,主要完成清除發(fā)送隊(duì)列,關(guān)閉網(wǎng)卡的發(fā)送、接收使能等工作。net_fxp_hard_start_xmit則負(fù)責(zé)啟動網(wǎng)卡發(fā)送數(shù)據(jù)[4]。
當(dāng)網(wǎng)卡設(shè)備接口處有數(shù)據(jù)傳進(jìn)來時就會觸發(fā)一個中斷,然后調(diào)用網(wǎng)卡接收程序net_fxp_rx函數(shù)進(jìn)行處理。當(dāng)網(wǎng)卡接收程序net_fxp_rx接收完數(shù)據(jù)或者網(wǎng)卡發(fā)送程序net_fxp_hard_start_xmit發(fā)送完數(shù)據(jù)后,也會觸發(fā)一個中斷,fxp_intr對接收到的中斷進(jìn)行檢測,掃描網(wǎng)卡設(shè)備的中斷寄存器,判斷是接收中斷還是發(fā)送完畢中斷,然后根據(jù)檢測結(jié)果跳轉(zhuǎn)到不同的處理函數(shù)去執(zhí)行,如果是接收中斷,則轉(zhuǎn)到net_fxp_rx_poll函數(shù)中去處理傳過來的數(shù)據(jù),并將其傳遞給上層協(xié)議。如果是包發(fā)送完畢中斷,則跳轉(zhuǎn)到net_fxp_tx_done函數(shù),通過該函數(shù)檢查網(wǎng)卡的發(fā)送狀態(tài)并記錄下發(fā)送數(shù)據(jù)的字節(jié)數(shù)等信息,檢查發(fā)送隊(duì)列判斷是否要接著發(fā)送數(shù)據(jù),還是發(fā)送數(shù)據(jù)任務(wù)已經(jīng)全部完成。若是已完成數(shù)據(jù)的發(fā)送,則更新緩沖區(qū)狀態(tài),然后返回到中斷處理函數(shù)[5]。
龍芯LS232 CPU是兼容MIPS指令集的,故在該CPU平臺下可采用MIPS的工具鏈。本文的開發(fā)環(huán)境是REHL 5.5操作系統(tǒng),gcc編譯器采用的是gcc-3.4.6版本,在制作交叉工具鏈時需要加上--target=mipsel-linux參數(shù)[6]。添加完網(wǎng)卡驅(qū)動后,需要重新編譯PMON,依次執(zhí)行以下命令:
編譯成功后,會在此目錄下生成一個gzrom.bin文件,將其燒入Nor Flash的0xbfc00000地址處即可[7]。
在添加完網(wǎng)卡驅(qū)動后,PMON重新編譯成功。啟動PMON后,通過使用ping程序測試(如圖3所示),測試結(jié)果表明網(wǎng)卡驅(qū)動功能正常。
圖3 ping測試Fig.3 Ping testing
本文是研究基于龍芯平臺下的一種Bootloader(PMON)的實(shí)現(xiàn)。分別分析了PMON的整體框架、初始化流程、PMON的源碼,在此基礎(chǔ)上進(jìn)行了網(wǎng)卡驅(qū)動的移植工作。代碼編寫及網(wǎng)卡移植后,完成單元測試、功能驗(yàn)證,PMON及網(wǎng)卡模塊功能正常、運(yùn)行穩(wěn)定。
[1]龍芯官方論壇.龍芯的歷程[EB/OL].(2011-05-04)[2011-06-09].http://www.loongson.cn/about_two.php?id=10&sub=龍芯的歷程.
[2]PMON-LinuxMIPS.PMON[EB/OL].(2010-02-08)[2011-06-10].http://www.linux-mips.org/wiki/PMON.
[3]aaaaatiger.PMON啟動流程[EB/OL].(2007-06-04)[2011-06-12].http://blog.csdn.net/aaaaatiger/article/details/1638182.
[4]宋寶華.Linux設(shè)備驅(qū)動開發(fā)詳解[M].2版.北京:人民郵電出版社,2010.
[5]CorbetJ.LINUX設(shè)備驅(qū)動程序[M].魏永明,耿岳,鐘書毅,譯.北京:中國電力出版社,2006.
[6]STRONGCHINA.Loongson GCC安裝和發(fā)布事項(xiàng) 2.2[EB/OL].(2008-10-07)[2011-06-23].http://bbs.lemote.com/viewthread.php?tid=18816&extra=page%3D1.
[7]CAIMOUSE.編譯PMON指南 [EB/OL]. (2006-12-24)[2011-06-23].http://www.lemote.com/bbs/viewthread.php?tid=3147&extra=page%3D1%26filter%3Ddigest.