高杰
(南昌大學共青學院 信息工程系,九江 332020)
從RISC到CISC的目的就是使得在CISC上運行的程序(OS+APP)能夠運行在RISC的體系結構上,轉化過程包括指令解碼、為OS建立運行環境等。嵌入式跨平臺體系結構如圖1所示。RISC體系結構的CPU有ARM處理器、MIPS處理器、龍芯、Godson等,CISC的平臺主要有X86系列。首先要完成的指令解碼包括ARM到X86(簡稱A2X86)、MIPS到 X86(簡稱 M2X86)、龍芯到 X86(簡稱D2X86)、Godson到X86(簡稱G2X86)。其次要完成BIOS功能。眾所周知,CISC上運行OS需要BIOS的支持,因此需要在指令解碼上一層為OS建立BIOS,即需要一個Vbios來支撐OS的運行。

圖1 嵌入式跨平臺體系結構
龍芯2E體系結構和X86(在本文中所指定的X86主要包括8086、80286、80386、80486)的體系結構有很大的差別,包括指令操作碼不同、尋址方式不同、內存管理不同、中斷處理機制不同等。從應用架構上看,其結構方式也不一樣,X86CPU體系結構經過多年的發展已經形成了一套運行微軟操作系統的標準。支持X86CPU的軟件也有自己的規范和要求,X86下的軟件非常豐富也很成熟,包括OS和應用軟件在內的軟件都是根據X86的架構設計的,所以這些軟件很難移植到像龍芯這樣的體系結構上。鑒于此,在龍芯2E硬件層上設計一個軟件層虛擬機程序,讓龍芯2ECPU上能夠運行X86下的OS和應用程序。具體的運行過程是,讓虛擬機程序能夠在系統加電后開始運行,來解析X86下的程序,從而使X86下的程序能夠運行在龍芯2E體系結構上。解釋X86程序的軟件叫Vx86虛擬機。簡單地說,Vx86虛擬機要完成的功能就是在龍芯2E的體系結構上建立一個可以運行X86程序的X86虛擬硬件環境。跨平臺虛擬機層次結構如圖2所示。
龍芯2E沒有像X86下BIOS那樣一個標準的初始化程序,它是由一個bootloader來完成初始化的。龍芯虛擬X86CPU需要完成以下幾個模塊:bootloader初始化程序、VBIOS程序、Vx86虛擬機程序。Vx86虛擬機在龍芯2E上的啟動過程如圖3所示。首要的任務是完成語言的識別和CPU處理的模擬,X86實現了在RISC的處理器上虛擬一個軟件X86處理器模型,包括其所有寄存器和運算、取指、加載、計算、保存結果的指令流水線,同時還翻譯所有X86系列的語言——X86二進制機器碼。

圖2 跨平臺虛擬機的層次結構

圖3 Vx86虛擬機在龍芯2E上的啟動過程
虛擬機的開發使用開源的開發環境,虛擬機是和操作系統無關的,所以在選擇開發環境時只需要選擇和硬件相關的開發環境即可,在這里使用龍芯2E的開源的 MIPS GCC編譯器,版本號3.4.6。編譯器運行在Linux操作系統下。開發語言選用C語言和MIPS匯編語言。
VBIOS是為了運行X86OS來初始化Vx86的BIOS程序。VBIOS的功能和X86BIOS的功能相同,是在Vx86運行起來的,其功能就是測試和初始化基本的外圍設備,初始化完成后就去引導操作系統。
CPU的虛擬就是用軟件仿真一個X86的CPU,主要的設計有CPU處理器虛擬設計、寄存器虛擬設計、中斷虛擬設計、取指虛擬設計、解碼虛擬設計5大模塊。Vx86 2.0設計中,這些設計相互間聯系緊密,沒有進行絕對的劃分,下面將其揉合到一起來說明。
CPU虛擬中的功能包括了中斷檢查、取指和指令執行等幾大模塊,CPU虛擬中斷程序流程如圖4所示。

圖4 CPU虛擬中斷程序流程
在虛擬CPU的無限循環中,每次在取指和指令執行前都要進行中斷檢查,如果有中斷到達,就先進行中斷處理,處理結束后再回到中斷時的位置繼續執行。在這些過程中要虛擬真實CPU的取指令、譯碼指令、中斷管理、內存管理等過程。下面定義的數據結構是為了完成CPU虛擬的核心數據結構。

Vx86在設計時采用了動態翻譯的設計方法。虛擬機每次取指后,將取回的指令翻譯成指令虛擬函數,接著執行這些翻譯后的虛擬函數,執行后將翻譯后結果保存在全局結構中,以方便下次使用。下一次CPU遇到同樣的地址時,先到保存的緩存區中查找,如果找到就直接從保存的全局緩沖區中使用,如果沒有找到就去重新翻譯。這樣的設計方法可大大提高虛擬機執行速度。
CPU的取指主要靠CS和IP/EIP來實現,在完成虛擬機時需要用軟件模擬CPU的取指過程。在保護模式下取指需要解決如下的問題:
①段式管理。
②頁式管理。
③指令跨頁問題。由于在80386模式下有頁式管理,頁式管理時把物理內存分成了大小相同的4KB塊。線性地址會把不連續的4KB物理內存映射到連續的線性地址空間,所以在虛擬時就要解決指令跨頁問題。
④指令指針移動問題。根據系統設計說明書可知,80386的指令最長可達16字節,指令不定長,所以每次在取指完要對eip進行修改。
⑤判斷訪問的物理內存是否越界。解碼虛擬主要完成的工作是根據80386的指令結構特點,將指令中的各個字段解析出來,然后根據各個指令碼的特點尋找指令虛擬函數。根據需求分析和系統設計可知,指令結構由指令碼前綴、指令碼、MOD-REG-R/M、SCALE-INDEX-BASE、偏移量、立即數幾部分組成。
在嵌入式系統中,bootloader是芯片復位后執行的一段代碼,這段代碼完成硬件的檢測與初始化、設置系統運行環境、引導OS,作用與PC啟動時的BIOS相當。bootloader的執行可以分成兩個階段,一是boot,二是loader。前一階段與平臺硬件緊密相關,用匯編語言來實現;后一階段與平臺無關,用C語言來實現,使代碼具有更好的可讀性和可移植性。與其他bootloader不同的是,本文的bootloader不是引導OS,而是引導Vx86虛擬機,并且與Vx86虛擬機一起編譯到一個BIN文件中,再下載到開發板上的Flash上。因此,引導時把Vx86虛擬機拷貝到RAM中,再跳轉執行就可以了。
設計bootloader首先要先了解目標平臺的CPU特點、異常處理、存儲映射關系、I/O設備操作方法。因此本文先介紹龍芯系統平臺的特點,再說明從CPU啟動開始,如何初始化系統平臺,直到引導Vx86執行。
龍芯開發板上的CPU是龍芯2E處理器。龍芯2E是實現了MIPS III指令集的通用RISC處理器,采用9級指令流水線,包括取指、預譯碼、譯碼、寄存器重命名、調度、發射、讀寄存器、執行、提交。龍芯2E使用了3個獨立的Cache:一級指令Cache,64KB的容量,采用4路組相聯的結構;一級數據Cache,64KB的容量,采用4路組相聯的結構;二級混合Cache,片上Cache,512KB的容量,采用4路組相聯的結構,使用的是寫回法。龍芯2E對程序地址空間的映射分為4部分,如圖5所示。

圖5 龍芯2E地址空間的映射關系
kuseg:0x000 0000~0x7FFF FFFF(低端2GB),這些是用戶模式下可用的地址。在帶有MMU的機器里,這些地址都將由MMU加以轉換。
kseg0:0x8000 0000~0x9FFF FFFF(512MB),只需要把最高位清零,這些地址就被轉換(translate)為物理地址,然后把它們連續地映射到物理內存中512MB大小的低字段 (0x0000 0000~0x1FFF FFFF)內。一般情況下,都是通過快速緩存對這段區域內的地址進行訪問。因此在Cache被正確地初始化之前,不要使用這些地址。
kseg1:0xA000 0000~0xBFFF FFFF(512MB),通過將最高3位清零的方法,把這些地址映射為相應的物理地址,然后象kseg0一樣,再映射到物理內存中512MB大小的低字段。但要注意,kseg1是不通過Cache存取的(uncached)。kseg1是唯一的在系統重啟時能正常工作的地址空間,這也是為什么重新啟動時的入口向量0xBFC0 0000會在這個區域內。
kseg2:0xC000 0000~0xFFFF FFFF(1GB),這段地址空間只能在核心態下使用并且要經過MMU的轉換。在MMU設置好之前,不要對其進行訪問。
對于本文來說,bootloader的工作主要在boot龍芯平臺,即初始化能運行系統的最小硬件環境,如北橋和南橋、DDRAM控制器、龍芯2E的Cache;初始化調試環境,如串口;然后把整個系統搬移到RAM中運行,再執行Vx86虛擬機。下面介紹詳細的過程。
當CPU啟動時,從地址0xBFC0 0000處取代碼執行,這個地址被映射到開發板上的Flash零地址偏移處,因此必須把bootloader燒錄到Flash的零地址偏移處才能正確執行。在連接腳本中有ENTRY(_start),程序的入口點是標號為start的代碼,從start開始的代碼被燒錄到Flash的零地址處偏移處。


“mtc0zero,COP_0_STATUS_REG”是CPU執行的第一條指令,把狀態寄存器清零。然后把COP_0_CAUSE_REG清零,接著是設置狀態寄存器的BEV位,這樣發生異常時,CPU從Flash上取異常處理的代碼。在異常處理時可以打印出觸發異常發生的原因、指令,便于調試。接著設置引導程序的堆棧空間,“la sp,stack”是把棧首地址給sp寄存器,“la gp,_gp”是把編譯器中的_gp全局地址給gp寄存器,這樣做是讓全局變量可以進行相對寄存器尋址。最后,執行Vx86虛擬機,直接通過函數調用來實現:VX86_Entry()。
本文討論的嵌入式跨平臺虛擬軟件技術應用,重點講述嵌入式跨平臺虛擬機CPU虛擬設計和bootloader設計。根據以上的分析可知龍芯2E虛擬80386、80486,甚至Pentium 4以下的機器都是可行的。龍芯2E已經提供了一個可行的硬件環境,實現X86平臺的軟件可以運行在MIPS平臺上。
[1]張凱龍.傳統OA的Linux中間件平臺移植技術及其實現[D].西安:西北工業大學,2003.
[2]戴梅萼,史嘉權.微型計算機技術及應用[M].4版.北京:清華大學出版社,2008.
[3]Dominic Sweetman.See MIPS Run[M].SanFranciso:Morgan Kaufmann Publishers,2008.
[4]李小波.龍芯2號功能部件半形式化驗證方法的研究與實現[D].北京:首都師范大學,2006.
[5]李會,鄔迪.嵌入式系統在工業控制中的應用[J].微計算機信息,2007(2).
[6]Bill Blunden.Virtual Machine Design and Implementation in C/C++[M].[S.I.],2003.