王 瓊,朱正發(fā)
(重慶郵電大學(xué) 通信與信息工程學(xué)院,重慶 400065)
近年來,隨著消費(fèi)類電子產(chǎn)業(yè)的高速發(fā)展,日益增長的嵌入式技術(shù)已經(jīng)不能滿足人們對嵌入式產(chǎn)品功能和性能的需求[1]。虛擬機(jī)技術(shù)的產(chǎn)生加速了嵌入式應(yīng)用領(lǐng)域的發(fā)展。嵌入式系統(tǒng)虛擬機(jī)可以在單芯片的硬件平臺上模擬多芯片的運(yùn)行,允許一個(gè)平臺同時(shí)運(yùn)行多個(gè)操作系統(tǒng),并且應(yīng)用程序可以在相互獨(dú)立的空間內(nèi)運(yùn)行而互不影響,從而顯著地提高設(shè)備的工作效率,縮短應(yīng)用軟件的開發(fā)周期,并且減少系統(tǒng)工作的芯片數(shù)量和企業(yè)的開發(fā)成本[2-3]。
隨著硬件平臺性能的不斷提升,虛擬機(jī)被廣泛地引入到嵌入式系統(tǒng)中。通過構(gòu)建嵌入式系統(tǒng)虛擬機(jī),可以保證通用操作系統(tǒng)和實(shí)時(shí)操作系統(tǒng)的并行運(yùn)行。虛擬機(jī)可以看成一個(gè)虛擬的硬件系統(tǒng),該系統(tǒng)將一個(gè)真實(shí)的嵌入式CPU虛擬成兩個(gè)虛擬的CPU,兩個(gè)虛擬CPU上可以分別運(yùn)行一個(gè)分時(shí)操作系統(tǒng)和一個(gè)(硬)實(shí)時(shí)操作系統(tǒng)(如圖1)[4]。
系統(tǒng)虛擬機(jī)的目的是在物理硬件和操作系統(tǒng)之間建立一層硬件抽象層,它將底層的物理硬件結(jié)構(gòu)進(jìn)行封裝,在操作系統(tǒng)移植過程中,操作系統(tǒng)就不需要了解底層物理信息,直接調(diào)用相應(yīng)的軟件接口就可以完成相應(yīng)的服務(wù)請求或設(shè)備配置[5]。
圖1 嵌入式虛擬機(jī)系統(tǒng)架構(gòu)
本文提出了一種基于Hopen虛擬機(jī)在Android手機(jī)平臺上實(shí)現(xiàn)雙操作系統(tǒng)之間數(shù)據(jù)交互的解決方案——虛擬管道(Virtual Pipe,Vpipe)以及NVM參數(shù)存取。
虛擬管道指在Android手機(jī)虛擬機(jī)平臺中實(shí)現(xiàn)基帶子系統(tǒng)(RTOS)和應(yīng)用子系統(tǒng)(Linux)之間數(shù)據(jù)交互的通道(如圖2)。主要功能是:讀寫數(shù)據(jù)(包括命令、狀態(tài)、控制數(shù)據(jù)等),在單CPU上完成雙操作系統(tǒng)間的信息傳遞等。
虛擬機(jī)提供32個(gè)雙向虛擬管道來實(shí)現(xiàn)雙操作系統(tǒng)的通信。每個(gè)虛擬管道都有對應(yīng)的ID號,并且都可以分別指定各個(gè)方向緩存的大小。所有Vpipe共享一個(gè)Vpipe中斷,使用中斷狀態(tài)位來快速判斷哪一個(gè)Vpipe有中斷產(chǎn)生。
Vpipe包括輸入緩存和輸出緩存兩種緩存機(jī)制,并且必須在管道啟動(dòng)前寫入相應(yīng)的寄存器中。需要對Vpipe進(jìn)行數(shù)據(jù)操作時(shí),先將數(shù)據(jù)的地址寫入到地址寄存器中,然后將字節(jié)數(shù)和操作指令寫入到指令寄存器中。
每個(gè)Vpipe工作的3種數(shù)據(jù)傳輸方式:
1)字節(jié)流管道:管道中傳輸?shù)氖亲止?jié)流,不區(qū)分?jǐn)?shù)據(jù)包的邊界。發(fā)送方一次發(fā)送的數(shù)據(jù)可能被接收方分若干次取出,發(fā)送方多次發(fā)送的數(shù)據(jù)也可能被合并,從而被接收方一次取出。
2)定長數(shù)據(jù)包管道:管道中傳輸?shù)氖枪潭ㄩL度的數(shù)據(jù)包。發(fā)送方每次只能發(fā)送一個(gè)數(shù)據(jù)包,接收方每次只能接收一個(gè)數(shù)據(jù)包。
3)指針管道:管道中傳輸?shù)氖侵羔樁皇菙?shù)據(jù)內(nèi)容。發(fā)送方每次只能發(fā)送一個(gè)指針,接收方每次只能接收一個(gè)指針。
目前只實(shí)現(xiàn)了往Vpipe里面讀寫數(shù)據(jù)的功能,管道通過Buffer來進(jìn)行數(shù)據(jù)的存儲,分為Vpipe_Outbuf和Vpipe_Inbuf。在上下行數(shù)據(jù)傳輸?shù)倪^程中盡量減少數(shù)據(jù)的拷貝:基帶到Android只有一次拷貝,Android到基帶沒有數(shù)據(jù)拷貝。
虛擬管道中參數(shù):Command(命令);Status(狀態(tài));Data(參數(shù))。
通信過程中,Linux組裝好數(shù)據(jù)(主要包括AT指令、PSCS數(shù)據(jù)、URC、NV參數(shù)等)發(fā)送到Vpipe,并一直查詢,等待狀態(tài)完成。
RTOS從Vpipe中獲取Linux發(fā)送過來的數(shù)據(jù)并進(jìn)行處理,處理完成后,需要先更新Status(操作成功,返回Success;否則,返回Fail);再根據(jù)命令的類型,有必要時(shí)也要更新Data;之后再更新Command;最后,通過Vpipe向Linux返回?cái)?shù)據(jù)。
以前的通信過程是:Android通過Vpipe發(fā)送AT指令到基帶,Vpipe接收到AT指令后通過區(qū)分不同的數(shù)據(jù)類型進(jìn)行函數(shù)封裝,然后給Android返回“OK”,Android收到“OK”后才能進(jìn)行下一條AT指令的發(fā)送。
現(xiàn)在需要解決的問題:當(dāng)Android給基帶發(fā)送AT指令后,還沒有收到“OK”響應(yīng)又發(fā)送了一條或者多條AT指令,這樣從基帶返回的“OK”就有多個(gè),Android如何區(qū)分返回的“OK”具體對應(yīng)于哪條AT指令。解決方案:通過在AT指令前面增加一個(gè)byte的AT標(biāo)識來區(qū)分不同的AT指令。
AT指令格式如圖3所示。
圖3 AT指令格式
Android和基帶之間AT指令的傳輸方式主要有并行傳輸和串行傳輸。并行傳輸:采用MUX標(biāo)準(zhǔn)協(xié)議,但是上下層目前都還沒有實(shí)現(xiàn),所以不考慮這種方式。串行傳輸:適用于AT指令的數(shù)據(jù)量較小且傳輸不是很頻繁的情況。由于目前應(yīng)用層采用的是串行傳輸方式,所以選擇串行傳輸方式。
Android讀寫AT指令的方式主要有同步讀寫和異步讀寫。異步讀寫:要在請求函數(shù)中實(shí)現(xiàn)狀態(tài)機(jī),并且需要修改當(dāng)前應(yīng)用子系統(tǒng)的超時(shí)機(jī)制,改動(dòng)較大。同步讀寫:當(dāng)前應(yīng)用層是通過線程信號來同步讀寫,為了實(shí)現(xiàn)并發(fā),要根據(jù)上層可能發(fā)起的業(yè)務(wù)類型創(chuàng)建多個(gè)請求線程,同時(shí)往AT命令管道寫數(shù)據(jù),當(dāng)線程收到AT的返回后,根據(jù)自定義數(shù)據(jù)中的標(biāo)志返回給對應(yīng)的請求線程。
綜上兩方面的考慮,采用串行傳輸AT指令、多請求線程、同步讀寫AT指令的方式來實(shí)現(xiàn)并發(fā)。
在Android手機(jī)方案中,NVM參數(shù)僅在基帶內(nèi)部使用,即虛擬機(jī)中的RTOS側(cè)使用,Linux不需要NVM參數(shù)。但NVM參數(shù)存放在Flash中,而Flash硬件的控制權(quán)又放于Linux中。所以,要實(shí)現(xiàn)基帶對NVM數(shù)據(jù)的存取,又不違背Flash硬件由Linux控制的原則,必須設(shè)計(jì)一套方案來實(shí)現(xiàn)基帶通過與Linux進(jìn)行必要的交互,完成NVM數(shù)據(jù)的存取。
NVM數(shù)據(jù)分為兩塊,一塊為Static參數(shù)(7 k),主要記錄產(chǎn)品固定參數(shù),出廠后不會再修改,但調(diào)試階段需要通過工程模式進(jìn)行修改;一塊為Dynamic參數(shù)(2 k),用于記錄設(shè)備工作過程中必須記錄的信息,如當(dāng)前小區(qū)相關(guān)信息,需要能夠在設(shè)備運(yùn)行過程中進(jìn)行動(dòng)態(tài)保存。
該方案直接使用Android的Flash Yaffs文件系統(tǒng),將其值保存到兩個(gè)特定文件中。這樣帶來的好處為:An?droid將數(shù)據(jù)維護(hù)交給Yaffs文件系統(tǒng),不用擔(dān)心壞塊處理;NV文件更新方便,不需要使用工具燒寫,直接通過Android的文件系統(tǒng)通道就可以進(jìn)行NV文件更換。兩個(gè)系統(tǒng)之間的數(shù)據(jù)交換使用Share Memory的方法,通知機(jī)制使用Vpipe。Init Process在啟動(dòng)基帶之前就將NV文件中的數(shù)據(jù)讀出寫入到Share Memory中,在正常工作過程中,Init Process接收到Driver的Uevent后將Share Memory數(shù)據(jù)寫入到文件系統(tǒng)對應(yīng)文件中。具體流程如圖4所示。
圖4 NVM數(shù)據(jù)存取流程圖
模塊之間的交互流程如圖5所示。在Android系統(tǒng)啟動(dòng)以后,首先啟動(dòng)Init Process,通過Android側(cè)的Vpipe Driver將Share Memory映射到用戶空間;然后將讀取文件系統(tǒng)中的NV文件數(shù)據(jù)寫入Share Memory;接著Android系統(tǒng)啟動(dòng)基帶軟件。
當(dāng)基帶側(cè)的NV Daemon Task需要將數(shù)據(jù)存入Flash時(shí),通過RTOS側(cè)的Vpipe發(fā)送Request,攜帶信息需要指明更新Static NV還是Dynamic NV;Linux側(cè)的Vpipe Driver收到數(shù)據(jù)后發(fā)送Uevent到Init Process,根據(jù)請求讀取Share Memory數(shù)據(jù)寫入文件系統(tǒng);完成后再通過Vpipe反饋ACK到基帶,NVM Daemon Task就完成一次寫操作。
圖5 Android手機(jī)虛擬機(jī)平臺NV數(shù)據(jù)存取流程圖
將DDR中一段區(qū)域(2 k+7 k,但要保證是4 k的整數(shù)倍,即必須分配12 k)固定指定為NV Share Memory,考慮到NV的數(shù)據(jù)交互不會很頻繁,可以使該區(qū)域不開啟Dchache,所以將其地址空間類型指定為設(shè)備空間,虛實(shí)地址映射固定,從而方便兩側(cè)直接使用。
共享內(nèi)存必須考慮沖突的情況。在開機(jī)NV Dae?mon Thread第一次向Share Memory寫數(shù)據(jù)時(shí),此時(shí)基帶還沒有加載,那么此時(shí)Memory一定是獨(dú)占的,這時(shí)沒有沖突。在接下來的流程中,Linux側(cè)只會去讀Memory,RTOS側(cè)只會去寫Memory。當(dāng)RTOS在任務(wù)中寫Share Memory時(shí),由于VM虛擬機(jī)保證RTOS任務(wù)的優(yōu)先級高于Linux進(jìn)程,所以整個(gè)過程都不會發(fā)生Daemon Thread讀動(dòng)作,因此RTOS的寫流程一定是安全的。但當(dāng)Linux在讀取時(shí),RTOS可以打斷這個(gè)流程發(fā)起新的寫入Memory過程,導(dǎo)致最后Linux讀取前后不一致的數(shù)據(jù)寫入到了NV文件中。所以,這里必須有機(jī)制進(jìn)行保護(hù)。
本方案提出的方法是:RTOS NVM Daemon Task向Linux側(cè)通過Vpipe發(fā)送請求以后,還必須關(guān)注響應(yīng),任務(wù)不需要等待,只需一次向Memory寫入,可以放棄CPU,等待一段時(shí)間再判斷。NV寫入對實(shí)時(shí)性要求不高,此處的延時(shí)可以接受。
為了應(yīng)對Linux系統(tǒng)中對NV文件寫入過程掉電導(dǎo)致Flash上的文件損壞的情況,在Android文件系統(tǒng)內(nèi)部維護(hù)4個(gè)NV bin文件,其中Static_nv_bak.bin與Dynam?ic_nv_bak.bin用于存放默認(rèn)配置,這兩個(gè)文件永不寫入;Static_nv.bin與Dynamic_nv.bin用于實(shí)時(shí)記錄。在NV數(shù)據(jù)的結(jié)構(gòu)體中用一個(gè)U16的字段來記錄數(shù)據(jù)的CRC校驗(yàn)值,當(dāng)讀取NV文件發(fā)現(xiàn)該校驗(yàn)值不對時(shí),讀取備份的NV文件并提供給基帶。同時(shí),在基帶內(nèi)部也有一套默認(rèn)配置(與An?droid文件系統(tǒng)中的備份文件內(nèi)容一致),當(dāng)基帶從Android獲取的數(shù)據(jù)校驗(yàn)不正確時(shí),基帶使用自己的默認(rèn)NV參數(shù)。
本方案的提出,解決了AT命令并發(fā)和NVM參數(shù)的存儲帶來的問題。采用串行傳輸和同步讀寫,提高了AT命令的處理效率,并且減少了時(shí)延。NVM數(shù)據(jù)存儲方案的提出,提高了NVM的讀寫速率,直接通過文件系統(tǒng)就可以快速地進(jìn)行NV文件的更換。
AT并行處理流程的調(diào)試結(jié)果:Android組裝AT命令(0x06:AT標(biāo)志;0x41542B4353510D:AT指令)并寫入到Vpipe(如圖6);通過中斷的方式觸發(fā)基帶Vpipe驅(qū)動(dòng)去讀取AT指令,在MCD適配層進(jìn)行記錄AT標(biāo)志并且去AT標(biāo)志,然后發(fā)送到協(xié)議棧(如圖7);協(xié)議棧收到AT指令后,返回“OK”,發(fā)送到MCD,再由MCD進(jìn)行AT標(biāo)志的填充,發(fā)送給Vpipe,最后發(fā)送到Android。
圖7 ARM log(截圖)
NVM數(shù)據(jù)存儲方案的調(diào)試結(jié)果(如圖8):基帶通過與Android交互實(shí)現(xiàn)對NVM參數(shù)的存取,此過程是通過Vpipe完成對Share Memory的操作。
圖8 NVM數(shù)據(jù)存儲基帶log(截圖)
本文通過引入虛擬管道技術(shù),提出了高效的NV參數(shù)存取方案。虛擬管道技術(shù),實(shí)現(xiàn)了Android和Nucleus的信息交互,包括AT指令、PSCS數(shù)據(jù)、URC數(shù)據(jù)等,完成了基帶和應(yīng)用之間的一系列數(shù)據(jù)的交互。NV參數(shù)存取方案的提出,實(shí)現(xiàn)了基帶對NVM數(shù)據(jù)的存取,實(shí)現(xiàn)了基帶通過與Linux進(jìn)行必要的交互,完成NVM數(shù)據(jù)的存取。
該方案的提出為實(shí)現(xiàn)單芯片上運(yùn)行雙操作系統(tǒng)的嵌入式系統(tǒng)提供了很好的解決方案,具有很好的應(yīng)用價(jià)值。
[1]英特爾開源軟件技術(shù)中心,復(fù)旦大學(xué)并行處理研究所.系統(tǒng)虛擬化原理與實(shí)現(xiàn)[M].北京:清華大學(xué)出版社,2009.
[2]張易知,徐國治.基于微內(nèi)核架構(gòu)的嵌入式系統(tǒng)虛擬化技術(shù)[J].電子產(chǎn)品世界,2009(4):47-49.
[3]MARTIN A,F(xiàn)LAKE J.嵌入式系統(tǒng)軟件調(diào)試跟蹤技術(shù)的發(fā)展趨勢[J].電子設(shè)計(jì)應(yīng)用,2005(7):16-18.
[4]崔燁.基于Linux平臺的智能手機(jī)軟件設(shè)計(jì)與實(shí)現(xiàn)[D].成都:電子科技大學(xué),2007.
[5]HU Xiao,CHEN Shuming.Applications of on-chip trace on debug?ging embedded processor[C]//Proc.Eighth ACIS International Confer?ence on Software Engineering,Artificial Intelligence,Networking,and Parallel/Distributed Computing.[S.l]:IEEE Press,2007:140-145.