吳亞杰, 劉衛東 ,, 曾小光
(1.中國海洋大學 信息科學與工程學院,山東 青島 266100;2.海信電器股份有限公司 山東 青島 200071)
龍芯是中國科學院計算所研制的通用CPU,已獲得MIPS科技公司的MIPS指令集的專利授權。龍芯1號的CPU主頻是266 MHz,最早在2002年開始產業化應用。龍芯2號主頻最高為1 GHz。龍芯3號于2010年推出成品,其設計的目標則在多核心的設計[1]。隨著龍芯的發展,龍芯CPU已不僅僅局限于個人桌面計算機領域,在嵌入式開發領域,龍芯CPU也同樣發展迅速,從2000年以來,越來越多的產品開始采用龍芯CPU。在計算機的體系結構中,無論是個人計算機、服務器還是嵌入式領域,基本輸入輸出系統BIOS是必不可少的,因為BIOS負責計算機系統的開機自檢、板級硬件初始化、加載操作系統內核以及基本I/O功能。
PMON是一款ROM-Monitor型的開源軟件,最初是為了LSI Logic MIPS R3000評估板的功能需求而開發的。經過多年發展,目前已經能夠支持MIPS、ARM、PPC和X86等CPU體系[2]。PMON具有強大而豐富的功能,除基本的I/O功能外,還包括CPU初始化、板級外設初始化與檢測、操作系統引導和調試等功能,并且 PMON支持從Flash、IDE、TFTP以及USB來啟動操作系統。
PMON源代碼的目錄結構如圖1所示,對于圖示中關鍵模塊說明如下:

圖1 PMON目錄結構Fig.1 PMON composition
1)Targets目錄 Targets目錄下存放的是與板級相關的代碼,該目錄下的每個子目錄都對應著某一個具體的開發板,當要將PMON移植到一個新的開發板時,就需要在該目錄新建一個子目錄,并向新建的子目錄中添加開發板相關的代碼,其中主要有以下幾個重要文件:start.S文件位于Targets/mips_board/mips_board目錄下,是整個PMON運行的起點;tgt_machdep.c文件位于 Targets/mips_board/mips_board目錄下,完成大部分板級外設的初始化工作;Targets/mips_board/dev目錄存放板級外設的驅動程序,所需移植的網卡驅動文件即存放于此目錄中;Targets/mips_board/conf目錄主要存放與硬件板相關的配置文件。大部分的文件都在Targets/mips_board/compile/mips_board目錄中完成編譯,調試用的pmon.gdb文件即位于此目錄。
2)conf目錄 Conf目錄下存放的是整個PMON系統的配置文件。
3)pmon目錄 該目錄下存放的是PMON公用的代碼,包括PMON所支持的各種命令,與CPU相關的代碼以及文件系統相關的代碼,主要有以下幾個子目錄:arch目錄下的子目錄存放的是與CPU相關的代碼;cmds目錄下存放的是各種在PMON中可以使用的命令文件,比如:ifup、devcp、g等命令,如果要想向PMON中添加新的命令,需要在此目錄下添加源文件、實現該命令功能即可;fs目錄下存放的是與各文件系統相關的代碼;common目錄下存放的是一些通用代碼,比如:命令解析、調試接口、異常處理、環境變量設置程序等部分;netio目錄下存放的是與網絡相關的命令的實現代碼。
4)Sys目錄 Sys目錄存放的是系統支持文件。
5)Lib目錄 Lib目錄存放的是庫的實現代碼。
6)zloader.mips_board目錄 最終燒寫到 Nand Flash中的的gzrom.bin文件就是在該目錄下經過鏈接而生成的。
當開發板上電之后,CPU即從0xBFC00000處取指令執行,整個PMON的入口位于start.S文件。該匯編程序主要完成CPU的初始化工作,設置異常向量入口、設置棧、初始化UART、初始化內存、初始化CACHE,并完成對PMON的代碼拷貝工作,即由Nor Flash搬運到SDRAM,以提高代碼執行速度[3]。最后PC指針跳轉到PMON的C入口initmips函數處繼續執行,從此進入C語言的執行環境。整個執行流程如圖2所示。

圖2 PMON初始化流程Fig.2 Flow chart of PMON initializing
在initmips函數中主要通過dbginit這個函數來完成大部分的初始化工作,主要有以下幾個函數來實現初始化工作:
1)__init函數: 初始化帶有 __attribute__ ((constructor))屬性的函數。
2)envinit函數:環境變量初始化。
3)init_net函數:網絡初始化,網卡設備的部分初始化也在這個函數中完成。
4)histinit函數:初始化歷史命令記錄。
在initmips函數完成初始化任務后,即跳轉到pmon/common/main.c中的main函數執行,在main函數中設置完一些參數后,即進入一個while循環,等待用戶輸入命令,while循環內部主要有兩個函數get_line和do_cmd函數。get_line函數一直試圖獲取用戶輸入的命令,而do_cmd函數負責解析命令,解析成功后,則分派相應的命令函數去執行;解析失敗則返回到while循環,繼續等待用戶輸入命令。執行到這里PMON已經完全運行起來了。此時如果需要加載內核,用load命令將內核加載到內存中,接著用g命令則傳遞參數給內核,并開始啟動操作系統。
PMON與其他Bootloader相比,其優勢在于PMON的調試功能強大。PMON本身能支持設置斷點命令b、查看/設置寄存器命令r、單步執行命令t、查看堆棧信息命令bt以及繼續執行命令c等調試相關的命令。b命令用于設置斷點,需要注意的是在PMON中最多可以支持32個斷點。r命令用于顯示/設置CPU寄存器,直接輸入r后會打印所有寄存器的信息。t命令用于單步執行。bt命令用于顯示當前堆棧信息。c命令用于繼續執行,即從當前斷點處繼續往下執行,相當于gdb的continue命令。除了上面列出的調試命令外,PMON還支持很多其它命令,比如:用于燒寫Nor Flash的devcp命令、顯示設備的devls命令、設置環境變量的set命令、顯示環境變量的env命令、加載文件的load命令、運行程序的g命令等。
以上重點描述了PMON的整體執行過程,接下來就要具體實現在PMON中的網卡移植過程。首先要在配置文件Targets/Hiview/conf/file.Hiview中添加如下部分:

上面這部分內容定義了網卡掛載的總線,以及需要編譯的網卡驅動的源代碼文件等,在重新編譯PMON時需要執行make cfg這個命令,此時會讀取配置文件,從而生成一個名為cfdata的數組,在PMON的啟動過程中會通過configure函數去配置已知的各個設備,并通過掃描有哪些設備掛在了總線上,PMON根據cfdata數組依次掃描設備。PMON首先通過config_rootfound函數來查找根設備,查找成功后再通過config_rootsearch函數來查找根設備上的子設備,子設備查找成功后則執行相應的子設備的掛載函數,通知PMON該子設備已找到,并將相應的子設備操作函數注冊到PMON中。
若網卡設備查找成功,則執行網卡的掛載函數,即fxp_attach函數,在fxp_attach函數中完成中斷處理函數fxp_intr的注冊,調用tgt_poll_register函數將中斷處理函數fxp_intr注冊到查詢列表poll_list上。在fxp_attach函數中完成的另外一個重要工作是將網卡驅動的函數添加到PMON中,以便PMON的上層接口能夠正確調用到網卡設備的下層驅動函數來實現功能,這里通過填充net_device結構體來實現,如下代碼即實現了該工作:

其中打開網絡設備通過net_fxp_open函數來完成,net_fxp_open主要工作是初始化網卡設備的相關寄存器,并分配用于接收、發送數據的緩沖區,設置好緩沖區的狀態。net_fxp_close函數則是在關閉網絡設備時調用,主要完成清除發送隊列,關閉網卡的發送、接收使能等工作。net_fxp_hard_start_xmit則負責啟動網卡發送數據[4]。
當網卡設備接口處有數據傳進來時就會觸發一個中斷,然后調用網卡接收程序net_fxp_rx函數進行處理。當網卡接收程序net_fxp_rx接收完數據或者網卡發送程序net_fxp_hard_start_xmit發送完數據后,也會觸發一個中斷,fxp_intr對接收到的中斷進行檢測,掃描網卡設備的中斷寄存器,判斷是接收中斷還是發送完畢中斷,然后根據檢測結果跳轉到不同的處理函數去執行,如果是接收中斷,則轉到net_fxp_rx_poll函數中去處理傳過來的數據,并將其傳遞給上層協議。如果是包發送完畢中斷,則跳轉到net_fxp_tx_done函數,通過該函數檢查網卡的發送狀態并記錄下發送數據的字節數等信息,檢查發送隊列判斷是否要接著發送數據,還是發送數據任務已經全部完成。若是已完成數據的發送,則更新緩沖區狀態,然后返回到中斷處理函數[5]。
龍芯LS232 CPU是兼容MIPS指令集的,故在該CPU平臺下可采用MIPS的工具鏈。本文的開發環境是REHL 5.5操作系統,gcc編譯器采用的是gcc-3.4.6版本,在制作交叉工具鏈時需要加上--target=mipsel-linux參數[6]。添加完網卡驅動后,需要重新編譯PMON,依次執行以下命令:


編譯成功后,會在此目錄下生成一個gzrom.bin文件,將其燒入Nor Flash的0xbfc00000地址處即可[7]。
在添加完網卡驅動后,PMON重新編譯成功。啟動PMON后,通過使用ping程序測試(如圖3所示),測試結果表明網卡驅動功能正常。

圖3 ping測試Fig.3 Ping testing
本文是研究基于龍芯平臺下的一種Bootloader(PMON)的實現。分別分析了PMON的整體框架、初始化流程、PMON的源碼,在此基礎上進行了網卡驅動的移植工作。代碼編寫及網卡移植后,完成單元測試、功能驗證,PMON及網卡模塊功能正常、運行穩定。
[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設備驅動開發詳解[M].2版.北京:人民郵電出版社,2010.
[5]CorbetJ.LINUX設備驅動程序[M].魏永明,耿岳,鐘書毅,譯.北京:中國電力出版社,2006.
[6]STRONGCHINA.Loongson GCC安裝和發布事項 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.