董 燕,黃 晨,王小麗,虞礪琨,于 倩
嵌入式軟件研制過程中,廣泛采用中斷服務機制來實現(xiàn)任務需求,但中斷系統(tǒng)的設計和實現(xiàn)過程中很容易引入資源訪問沖突錯誤.由于中斷觸發(fā)的隨機性和不確定性,動態(tài)測試過程中難以發(fā)現(xiàn)和定位該類問題,造成軟件相關的安全性可靠性測試降低,加大了軟件維護成本,實踐表明航天嵌入式軟件后期測試發(fā)現(xiàn)問題至少50%為中斷沖突問題[1].因此在軟件設計及靜態(tài)測試階段進行中斷沖突分析是十分有必要的.
目前,中斷沖突技術(shù)及相關的工具的研究日漸增多[2-3],但是大多數(shù)還停留在理論研究階段,實際進行應用的還較少,文獻[4]重點針對單變量訪問序模式,基于抽象解釋,提出了一種支持過程間分析、中斷并發(fā)分析的高效檢測方法,但由于相關的沖突對象和場景識別不夠充分和確定,導致在應用過程中存在信息誤報率大,操作困難等實際問題[5-7].本文基于航天嵌入式軟件近二十年第三方測試發(fā)現(xiàn)的中斷沖突問題研究的基礎上,識別和總結(jié)了中斷訪問沖突模式,并結(jié)合典型實例解析說明了沖突機理,對相關中斷沖突場景和分析方法進行了較為全面的分析和總結(jié).
中斷訪問沖突本質(zhì)是對共享資源的訪問存在競爭引起,因此識別競爭資源是沖突分析的首要步驟.競爭資源,也就是可能引入中斷沖突的參數(shù),包括任意一個變量,標準芯片端口、FPGA端口、絕對存儲地址,這些參數(shù)只要在不同優(yōu)先級的子程序中被引用,均是中斷沖突分析對象[8-9].另外還有規(guī)定的軟件固定操作序被軟件其他操作意外打斷的情況也有可能引入訪問沖突問題.但對這些對象的訪問并不是一定會引入中斷沖突,具體在什么情況下會引入沖突還需要具體進行分析.
在此結(jié)合目前測試中已經(jīng)發(fā)現(xiàn)的中斷沖突問題,通過靜態(tài)的分析參數(shù)類型及參數(shù)訪問序,研究中斷數(shù)據(jù)訪問沖突及機理,繼而形成靜態(tài)的分析方法,能夠有效彌補動態(tài)測試在發(fā)現(xiàn)數(shù)據(jù)訪問沖突問題上具有隨機性和不確定性的缺陷,提升發(fā)現(xiàn)數(shù)據(jù)訪問沖突的準確率.
依據(jù)處理器對參數(shù)的訪問形式、多個變量之間的關系,將參數(shù)類型分為3類:
1) 原子變量
處理器對當前變量進行的一次讀或者寫訪問時僅為單條語句,不存在被其他操作打斷的可能.
2) 非原子變量
處理器對當前參數(shù)進行一次讀或者寫訪問時必須分解為多條語句執(zhí)行,比如數(shù)組變量(例如,char a[5]),多于處理器字長變量(例如,處理器8051機器字長為8 bits,軟件定義int型變量對應16 bits).
3) 關聯(lián)變量
兩個或多個變量有依賴關系或者是同步關系,如一個數(shù)組中的多個元素拼接成為另外一個變量;一個變量是另外兩個或幾個變量的校驗和;一個變量表示指令號與另一個變量表示指令內(nèi)容一一對應.
可以較為容易理解的是,當處理器對變量的訪問僅為一條匯編語句(一條匯編語句對應一個指令周期)時,即便是多個子程序同時對其進行訪問,也不會存在因為變量內(nèi)容不同步引入訪問沖突問題,在此重點針對非原子變量、關聯(lián)變量的典型沖突場景進行分析,說明沖突發(fā)生的機理和分析方法,后續(xù)不再針對原子變量進行訪問沖突分析.
該類型變量長度超出了對應處理器字長,雖然源代碼級上只有一條語句,但編譯后需要分成多條匯編語句步驟執(zhí)行,下面以單片機8051和DSP TMS320C6000芯片為例,通過分析匯編代碼驗證中斷沖突發(fā)生的場景.
8051為8位處理器(大端結(jié)構(gòu),低地址存高字節(jié)數(shù)據(jù),高地址存低字節(jié)數(shù)據(jù)),定義變量c為int型(16位),則c對應2字節(jié)長度:
圖1 單片機2字節(jié)變量沖突場景Fig.1 Conflict scene of single chip two bytes variable
上圖1中一條給變量c賦值的C語言代碼,對應的匯編代碼為多條語句,分為先寫入低字節(jié)數(shù)據(jù),再寫入高字節(jié)數(shù)據(jù)等多個步驟進行.
當主程序在寫變量c兩個字節(jié)過程中如果發(fā)生中斷并進行讀c的操作,此時讀取到的c值高低字節(jié)數(shù)據(jù)并不同步.
TMS320C6000為32位處理器,定義變量a為long long int型(64位),對應2個字長度:
圖2 DSP 2個字變量沖突場景Fig.2 Conflict scene of DSP 2 byte variable
圖2中主程序中對變量a的賦值操作分為兩步,先寫低32位,再寫高32位,如果在寫操作過程中發(fā)生中斷讀變量a,會導致中斷中讀取到的變量a高低字數(shù)據(jù)不同步.
表1 Franklin C51的基本數(shù)據(jù)類型Tab.1 Basic data type of Franklin C51
嵌入式軟件常用的芯片如MCS-51、SPARC、DSP處理器的字長分別為8位、32位和32位,為了輔助分析,針對不同的數(shù)據(jù)類型,給出對應的長度說明如表1~3所示.表1中的sfr是C51中定義特殊功能寄存器所使用的一種專用關鍵字,與標準C不兼容,只適用于C51.
表2 SPARC的基本數(shù)據(jù)類型Tab.2 Basic data type of SPAR
表3 DSP芯片數(shù)據(jù)類型Tab.3 Basic data type of DSP
注:“-”表示該芯片不存在當前數(shù)據(jù)類型.
當數(shù)組元素中的多個變量存在關聯(lián)時,應保證相互關聯(lián)變量讀寫操作的匹配性.
(1) 數(shù)組變量中的多個元素存在關聯(lián)
在代碼實現(xiàn)過程中,一般對數(shù)組變量的訪問操作是由多條語句構(gòu)成,對應的中斷場景也最易識別,下面以實例進行分析:
參數(shù):系統(tǒng)時間碼System_time[6]:共6字節(jié),前4字節(jié)為s,后2字節(jié)為ms;主程序?qū)ζ溥M行讀操作,中斷服務子程序?qū)ζ溥M行寫操作,具體代碼實現(xiàn)如圖3所示:
圖3 數(shù)組變量沖突實例Fig.3 Conflict scene of array variable
主程序一次讀取系統(tǒng)時間碼過程中發(fā)生中斷進行時間寫后返回,然后主程序繼續(xù)讀,讀取到的時間碼的3字節(jié)數(shù)據(jù)不同步.
(2) 多個獨立的變量之間存在關聯(lián)
例如:溫度參數(shù)t1,t2,對應累加和變量t3,均為單字節(jié)變量.主程序讀取t1,t2進行計算校驗和,中斷服務子程序讀取t1,t2和t3進行遙測下行:
圖4 關聯(lián)變量沖突場景Fig.4 Conflict scene of related variables
上述圖4變量如果獨立分析,則均不會存在數(shù)據(jù)訪問沖突,但由于t3與t1、t2存在一定的對應關系,則在代碼設計過程中隱含的需求就是三者數(shù)據(jù)必須同步,否則當主程序讀取t1、t2后計算t3之前產(chǎn)生中斷,則遙測下行的t3與t1、t2不對應.
針對參數(shù)類型進行中斷沖突分析時,除需要進行每個變量的類型分析外,還需要進行關聯(lián)變量的識別,關聯(lián)變量的識別應在軟件研制過程中的需求分析階段進行,在數(shù)據(jù)字典中進行明確定義.
針對多于處理器字長變量、數(shù)組變量、關聯(lián)變量,一次讀或?qū)懺L問過程中可能引入數(shù)據(jù)訪問沖突的場景及后果總結(jié)歸納如下:
(1) 主程序讀—中斷寫,會導致主程序讀取到的數(shù)據(jù)不同步;
(2) 主程序?qū)憽袛鄬?,會導致主程序?qū)懭氲臄?shù)據(jù)值不同步;
(3) 主程序?qū)憽袛嘧x,會導致中斷讀取到的數(shù)據(jù)值不同步;
(4) 主程序讀—中斷讀,要針對具體情況分析是否存在不同步的可能,一般來說存在不同步的可能性較小.
以上是針對幾種參數(shù)類型進行一次訪問操作過程中引入的數(shù)據(jù)不同步場景分析.針對同一個參數(shù)的多次訪問過程中,如果存在多次訪問操作被中斷打斷的可能時,需要從參數(shù)訪問序角度分析是否存在訪問沖突.
一個變量在主程序、各級中斷服務子程序中多次進行讀寫,哪些會在讀寫過程中引入變量訪問沖突呢,在此以中斷中有讀操作和寫操作進行分類,并通過實例加以分析說明.
3.1.1 中斷寫操作時的主程序訪問序
(1) 主程序中有讀讀操作序
圖5代碼針對變量rsCount的訪問就是主程序進行連續(xù)兩次讀,中斷服務子程序中進行一次寫的操作.該種形式的訪問序會在主程序第一條讀語句執(zhí)行后,第二條讀語句執(zhí)行前,如果產(chǎn)生中斷,會導致第二次讀出的數(shù)值與第一次不同.通過對本實例的分析,兩條讀語句對應的變量值應該為同一時刻的數(shù)值,上述代碼存在訪問沖突,在此稱為“讀讀之間產(chǎn)生寫”,通過該實例可以總結(jié)如下:
針對“讀讀之間產(chǎn)生寫”訪問序,分析是否發(fā)生中斷沖突的途徑就是確認兩次或多次讀語句對應該變量值是不是要求為同一時刻的值,如果要求是同一時刻的值,即多次讀的過程中不能被中斷改寫,則該“讀讀之間產(chǎn)生寫”訪問序就存在中斷訪問沖突.
針對兩次或多次讀語句對應該變量值是不是要求為同一時刻的值,需要結(jié)合代碼實現(xiàn)邏輯及軟件功能進行測試需求分析,一般在同一個模塊中連續(xù)讀操作的訪問沖突概率較大.
圖5 主程序讀-讀操作序場景Fig.5 Main program reading reading-interrupt reading operation order
(2) 主程序中有讀寫操作序
從代碼實現(xiàn)角度,針對讀寫訪問序,體現(xiàn)為兩種形式,多條源代碼語句和一條源代碼語句.
①多條源代碼語句完成讀寫
多條源代碼語句完成的讀寫典型過程如下圖主程序部分,對應的沖突場景如下:
圖6 主程序讀寫-中斷寫操作序場景Fig.6 Main program reading writing-interrupt writing operation order
針對圖6形式的讀寫訪問序,如果中斷中寫操作,則會在主程序讀出變量a后,給a重新賦值之前,如果產(chǎn)生中斷,則會造成中斷給a賦值的操作被主程序的重新寫覆蓋,導致優(yōu)先級高的程序功能寫功能失效,即存在訪問沖突.
②一條源代碼語句完成讀寫
如c++,a=a+b.該類語句編譯后對應的匯編代碼通常均有多條語句組成,完成對應的讀寫操作.在此列出幾種處理器8051系列,TSC695F及DSPTMS3206701對應的匯編語句如圖7所示:
圖7 一條源代碼讀寫對應多條匯編代碼實現(xiàn)Fig.7 Assembly code related to c source code
經(jīng)分析匯編代碼進行驗證,針對單條的讀寫語句,對應的匯編代碼均是先從原變量中讀出原值到寄存器,在寄存器中完成運算操作,然后回寫到原變量中,對應的訪問沖突原理與多條語句完成讀寫相同,針對一條源代碼讀寫操作存在訪問沖突的場景,僅從源代碼級別進行分析時無法發(fā)現(xiàn)沖突,需要翻譯成對應的匯編代碼進行分析,具體沖突場景如圖8所示.
(3) 主程序中有寫讀操作序
寫讀操作序的訪問流程如圖9所示.
圖8 主程序讀寫-中斷寫操作序場景Fig.8 Main program reading writing-interrupt writing operation order
圖9 主程序?qū)懽x-中斷讀操作序場景Fig.9 Main program reading writing-interrupt reading operation order
針對上述形式的寫讀操作序是否會引入訪問沖突,需要結(jié)合代碼實現(xiàn)邏輯,確認當前模塊中對變量的讀操作的來源:如果來源是當前模塊內(nèi)此前寫入的內(nèi)容,則該讀操作應與前面的寫操作不能被中斷打斷,否則會引入訪問沖突;如果來源不限定本模塊寫入內(nèi)容,則不會存在訪問沖突.
(4) 主程序中存在只寫操作
主程序和中斷服務子程序均有寫操作的變量,理論上會存在中斷沖突導致中斷的寫操作失效,但此類沖突對軟件功能是否有影響,需要結(jié)合功能背景及匯編代碼進行影響分析,一般情況下這種訪問序引起的中斷沖突會造成軟件錯誤.
3.1.2 中斷讀操作時的主程序訪問序
(1) 主程序中有寫寫操作序
圖10場景中,如果中斷在第一次給TM[0]賦值語句后產(chǎn)生,則中斷中讀到的數(shù)據(jù)并不是本周期的最終結(jié)果,可能會導致后續(xù)操作錯誤.
主程序中有寫寫操作,中斷中有讀操作時,此時讀取到的數(shù)據(jù)可能不是最終結(jié)果,導致功能實現(xiàn)錯誤.
圖10 主程序?qū)憣?中斷讀操作序場景Fig.10 Main program writing writing-interrupt reading operation order
(2) 主程序中有其他操作序
當中斷中存在讀操作,主程序中存在讀寫操作、讀讀操作、寫讀操作的訪問序時,需要根據(jù)中斷中讀操作時效性的要求進行分析,如果要求中斷中讀取到的是主程序中最新寫入的數(shù)據(jù),則可能存在數(shù)據(jù)訪問沖突;如果不要求中斷中立刻讀取到主程序中最新寫入的數(shù)據(jù),則不存在數(shù)據(jù)訪問沖突問題.
3.1.3 固定操作序沖突場景分析
固定操作序是指某項功能對應的一組固定執(zhí)行動作,分布于一個或多個子程序中,涉及一個或多個變量,這些變量在當前固定動作中不能被外界意外改動.具體可分為一個子程序中的一個參數(shù)(端口)的固定操作序、多個子程序中的一個參數(shù)(端口)的固定操作序、多個子程序的多個參數(shù)(端口)的固定操作序等.在此以一個子程序中一個參數(shù)和多個子程序中一個參數(shù)為實例進行說明.
(1) 一個子程序中一個參數(shù)的固定操作序
以CAN控制器MCP2515通過SPI接口擴展方式的讀操作過程對應一組操作序為例進行說明,向硬件端口的一系列操作如果被其他操作打斷,會造成讀操作失效.讀操作序的基本過程如下:
1) CS片選拉低;
2) 往SPI數(shù)據(jù)端口寫入命令0x03表示準備讀數(shù)據(jù);
3) 往SPI數(shù)據(jù)端口寫入準備讀出數(shù)據(jù)的對應地址;
4) 往SPI數(shù)據(jù)端口寫入任意一字節(jié)數(shù);
5) 從SPI數(shù)據(jù)端口讀出數(shù)據(jù);
6) CS片選拉高.
圖11場景中當主程序進行讀操作序過程中向芯片執(zhí)行寫入任意數(shù)0x55后,若發(fā)生中斷進入寫操作序,則在中斷返回主程序后從SPI0DAT讀出的數(shù)據(jù)不再是外部設備送入的內(nèi)容,可能為中斷服務子程序?qū)懭氲闹?x0EB,最終導致主程序中讀出的不是預期內(nèi)容,造成讀操作失敗.
圖11 同一個參數(shù)固定讀操作序沖突場景Fig.11 Conflicting scenario of reading sequence to the same parameter
(2) 多個子程序中一個參數(shù)的固定操作序
某嵌入式軟件對OC門指令的輸出操作過程為:向端口0x1111寫入指令對應的編碼0xXX以啟動控制脈沖發(fā)送,持續(xù)20 ms±5 ms后,再向遙控端口0x1111寫入0x00結(jié)束控制脈沖發(fā)送,如圖12所示.
圖12 向同一個參數(shù)寫操作序沖突場景Fig.12 Conflicting scenario of writing sequence to the same parameter
為保證操作序的正常執(zhí)行,分布于不同優(yōu)先級子程序(主程序,定時器中斷服務子程序)中的操作序不應被外界打斷,但是該軟件會發(fā)出不同種類的OC門指令.如果軟件在啟動20 ms定時后繼續(xù)執(zhí)行其他代碼過程中再次滿足發(fā)OC門指令且當前時間間隔小于20 ms,會重新執(zhí)行主程序中定時20 ms操作,導致上一條OC門指令的執(zhí)行過程被意外終止,即未在20 ms后發(fā)結(jié)束控制脈沖,輸出的OC門指令高電平寬度不滿足性能指標要求.
針對某參數(shù)存在連續(xù)的多次訪問操作序時,需要注意以下內(nèi)容:
(1) 能夠完成讀寫功能的一條源代碼(如c++,a=a+b),如果中斷服務子程序中有寫操作,一定會引入該參數(shù)的訪問沖突,導致參數(shù)數(shù)值錯誤;
(2) 一個參數(shù)在不同優(yōu)先級子程序中均被訪問時,針對低優(yōu)先級子程序中的讀寫操作序如果不能被外界打斷,當有高優(yōu)先級子程序?qū)ζ浯嬖谏鲜稣f明的訪問時,一定會引入該參數(shù)的訪問沖突,導致參數(shù)數(shù)值錯誤;
(3) 參數(shù)訪問序的設置需要結(jié)合代碼設計進行分析,確定其不可被打斷的操作序有效范圍,例如:多條語句構(gòu)成的一個數(shù)學計算、一個獨立的邏輯處理,后續(xù)參數(shù)訪問應是依據(jù)前面訪問邏輯獲取的結(jié)果.
(4) 針對固定操作序,對應的操作序在執(zhí)行過程中都不能被打斷,如果被打斷且高優(yōu)先級程序中存在寫操作會導致讀操作失效.
(5) 固定的操作序可能分布于一個或多個子程序中,一旦啟動后則不能因為任何其他外部條件意外終止,否則會導致操作序失效.
本文從參數(shù)類型及參數(shù)訪問序兩個角度對中斷數(shù)據(jù)沖突進行了原理分析和方法研究.從參數(shù)類型進行分析:當主程序和中斷中存在同時訪問的共享參數(shù)資源是數(shù)組變量、多字節(jié)變量、關聯(lián)變量時,當主程序或者中斷中同時存在寫操作時會造成數(shù)據(jù)不同步,存在訪問沖突問題.從參數(shù)訪問序進行分析情況會比較復雜一些,確保主程序中讀寫操作不會被中斷改寫;中斷的寫操作不會被主程序覆蓋;中斷中的讀操作是最終結(jié)果,而不是中間計算過程;除此之外還有些情況需要結(jié)合具體應用背景進行分析.針對固定操作序,對應的操作序在執(zhí)行過程中都不能被打斷,如果操作序執(zhí)行過程中,被高優(yōu)先級子程序打斷且對操作序中涉及的資源有寫操作,則導致當前正在執(zhí)行的固定操作序中所讀數(shù)據(jù)不是當前操作序的結(jié)果,而是高優(yōu)先級子程序操作序中的內(nèi)容.如果操作序執(zhí)行的過程中,存在新條件引起該操作序被重新啟動,會導致當前正在進行的操作序被意外終止.
由于中斷數(shù)據(jù)沖突的發(fā)生具有不確定性和隨機性,文中描述的沖突場景不可能在所有的動態(tài)測試過程中都會出現(xiàn),這種靜態(tài)的分析方法相比較動態(tài)的測試更容易發(fā)現(xiàn)這種小概率隨機性問題且容易實施,操作性較強.在軟件設計和測試過程中增加專門的中斷數(shù)據(jù)沖突分析有助于充分、全面、準確定位沖突問題,目前,這種分析方法目前已經(jīng)應用于第三方實際測試過程中,并取得了較好的應用效果,發(fā)現(xiàn)了大部分中斷沖突問題.本文列舉的實例和分析方法有助于建立完善的缺陷模式庫,在自動化檢測工具中構(gòu)建上述模型,可自動識別訪問沖突問題.為自動化工具在檢測數(shù)據(jù)競爭的準確性、高效性方面起到參考和借鑒作用.