案例研究 | 我的AUTOSAR程序在S32G上運(yùn)行,怎么老是跑進(jìn)異常?!【Classic AUTOSAR】

導(dǎo)言
最近幾個(gè)并行在做的Classic AUTOSAR項(xiàng)目都是基于時(shí)下最廣受關(guān)注的芯片之一—— S32G。
在S32G上調(diào)試的代碼越來越多之后,代碼跑著跑著進(jìn)入異常的情況也非常多,調(diào)試過嵌入式的都懂,一旦進(jìn)入錯(cuò)誤或者異常,往往要面對一堆異常處理函數(shù),而且還是匯編!雖說咱也不是不懂匯編,但是調(diào)起來肯定不如調(diào)試C代碼直觀。
那么問題來了,怎么能夠快速解決這個(gè)問題呢?現(xiàn)在也不知道是怎么了,嵌入式軟件也開始搞敏捷開發(fā),兩周一個(gè)sprint,一直在趕工??!
這個(gè)時(shí)候我們更應(yīng)該冷靜下來想想可以怎么解決它。
首先我們應(yīng)該想想有關(guān)S32G的幾個(gè)問題:
S32G是什么公司的芯片?
NXP!
S32G適用場景是什么?
網(wǎng)關(guān)!
S32G是基于什么架構(gòu)的?
Cortex-M7!
OK,這個(gè)三連回答的非常好,既然知道它是Cortex-M7架構(gòu)的,那么就好辦了。
什么,Cortex-M是什么?我給你指個(gè)路:Arm Product Filter – Arm? (https://www.arm.com/product-filter?families=cortex-m&showall=true)

Cortex-M還分了很多系列,其他我們暫且不表,主要還是先來了解下S32G對應(yīng)的M7。

一般來說,芯片是有相應(yīng)的寄存器來告訴我們發(fā)生了什么樣的異常/錯(cuò)誤,對于Cortex-M,有什么寄存器可以提供這些信息呢?
從第一步分析的角度來說,相關(guān)的寄存器有兩個(gè),Configurable Fault Status Register(CSFR)和Hard Fault Status Register(HFSR)。
?
可配置故障狀態(tài)寄存器 Configurable Fault Status Registers (CFSR)
這一個(gè)32位寄存器包含了何種故障導(dǎo)致進(jìn)入異常的信息,一共和三種狀態(tài)有關(guān):

USFR – UsageFault Status Register
BFSR – BusFault Status Register
MMFSR – MemManage Status Register
使用故障狀態(tài)寄存器 UsageFault Status Register (UFSR)
UFSR占2個(gè)字節(jié)長度,代表和內(nèi)存訪問無關(guān)的故障,例如嘗試執(zhí)行非法指令 ,或者嘗試進(jìn)入非法狀態(tài)。

DIVBYZERO?- 發(fā)生了除零操作??赏ㄟ^CCR寄存器配置是否開啟此故障檢測。
UNALIGNED?- 發(fā)生了未對其地址訪問操作,例如訪問了一個(gè)沒有8字節(jié)對齊的uint64_t類型變量。對于4字節(jié)及以下的非對其地址訪問,也可以通過CCR寄存器配置是否開啟檢測。
NOCP?- 在協(xié)處理器不存在或者未使能的情況下,執(zhí)行了Cortex-M協(xié)處理器指令。一個(gè)普遍的場景是在編譯選項(xiàng)當(dāng)中使用-mfloat-abi=hard-mfpu=fpv4-sp-d16進(jìn)行浮點(diǎn)操作,但在程序啟動/執(zhí)行時(shí)并未使能協(xié)處理器。
INVPC?-?EXC_RETURN一致性檢查錯(cuò)誤。
INVSTATE?- 處理器嘗試使用非法的Execution ? ? ?Program Status Register?(EPSR) 值執(zhí)行指令。ESPR寄存器追蹤處理器是否在thumb狀態(tài)。 寫匯編代碼時(shí)容易有這種錯(cuò)誤。
UNDEFINSTR?- 執(zhí)行了未定義指令,如果在異常處理推出時(shí)棧損壞,會觸發(fā)這個(gè)異常。或者,代碼路徑應(yīng)該無法訪問到的時(shí)候,編譯器也可能會生成未定義指令。
總線故障狀態(tài)寄存器 BusFault Status Register (BFSR)
BFSR占1個(gè)字節(jié)長度,代表預(yù)取指令或者內(nèi)存訪問錯(cuò)誤。

BFARVALID?- 代表位于0xE000ED38地址的32位寄存器Bus Fault Address ? ? ?Register?(BFAR), 存儲了觸發(fā)這個(gè)故障的地址。
LSPERR?&?STKERR?- ? ? ?floating-point lazy state錯(cuò)誤或者異常入口時(shí)stack錯(cuò)誤
UNSTKERR?- 從異常返回時(shí)發(fā)生故障,比如異常處理時(shí)棧損壞,或者SP指針被改變而內(nèi)容沒有被正確初始化。
IMPRECISERR?- 硬件是否可以決定故障的確切位置。
PRECISERR?- 是否進(jìn)入異常前的指令導(dǎo)致錯(cuò)誤
IMPRECISERR對于調(diào)試bus error非常重要,畢竟它代表了我們是否能夠直接獲取導(dǎo)致異常的指令在何處。指令獲取和數(shù)據(jù)載入,在Cortex-M設(shè)備上總是會產(chǎn)生同步故障,而存儲操作則可能產(chǎn)生異步故障,因?yàn)橛械臅r(shí)候?qū)懭霐?shù)據(jù)會先被緩存起來,然后才會寫進(jìn)數(shù)據(jù),以避免流水線停留,所以PC指針先于數(shù)據(jù)存儲完畢之前移動,執(zhí)行其他指令。
所以,當(dāng)出現(xiàn)imprecise bus error時(shí),你可能需要在報(bào)告的故障地址附近看看是否有可能導(dǎo)致異常的存儲操作。如果MCU支持ARM的Embedded Trace Macrocell(ETM),那么也可以通過調(diào)試器查看最近被執(zhí)行的指令歷史。
Auxiliary Bus Fault Status Register (ABFSR)
當(dāng)IMPRECISE error發(fā)生時(shí),我們可以利用僅在Cortex-M7設(shè)備上才有的ABFSR寄存器,查看何種內(nèi)存總線產(chǎn)生的故障。

這里的AXIM,EPPB,AHBP,DTCM,ITCM都是接口類型,這里不再做展開。
內(nèi)存故障寄存器MemManage Status Register (MMFSR)
MMFSR報(bào)告內(nèi)存保護(hù)單元故障。
一般地,MPU故障只在MPU配置并使能的情況下才可能會被觸發(fā),然而,例如嘗試在系統(tǒng)地址的范圍執(zhí)行代碼等情況下,也會觸發(fā)內(nèi)存訪問錯(cuò)誤。

MMARVALID?- 32位寄存器MemManage Fault Address Register?(MMFAR)是否有效保存了期望訪問的內(nèi)存地址
MLSPERR?&?MSTKERR?- 典型的錯(cuò)誤是,MPU用來檢測棧溢出時(shí),lazy state ? ? ?preservation或exception entry時(shí)的故障
MUNSTKERR?- 從異常返回時(shí)發(fā)生的故障
DACCVIOL?- 數(shù)據(jù)訪問導(dǎo)致的錯(cuò)誤
IACCVIOL?- 指令執(zhí)行導(dǎo)致的MPU或Execute Never (XN) 故障(0xE0000000及更高的地址是無法被執(zhí)行的)
HardFault Status Register (HFSR)

HFSR寄存器帶有導(dǎo)致HardFault的原因信息。
DEBUGEVT?- debug子系統(tǒng)未被使能的情況下,發(fā)生了debug事件,也即執(zhí)行斷點(diǎn)指令
FORCED?- 上文提到的可配置故障升級為了HardFault,有可能是因?yàn)榭膳渲霉收蟞andler沒有被使能,或者在handler中處理時(shí)又發(fā)生了故障
VECTTBL?- 由于從向量表中讀出地址時(shí)發(fā)生故障。一般不會發(fā)生,但如果向量表中有'壞'地址并且非預(yù)期中斷發(fā)生時(shí),還是可能產(chǎn)生這個(gè)故障
恢復(fù)現(xiàn)場
為了修復(fù)故障,我們需要知道故障發(fā)生時(shí)正在執(zhí)行什么代碼,因此我們需要在進(jìn)入異常時(shí)獲取寄存器的狀態(tài)。
如果你有調(diào)試器,那很好,把斷點(diǎn)打在異常handler,

進(jìn)入異常前,硬件總是會將一些寄存器的內(nèi)容push在棧頂。Cortex-M有兩個(gè)SP指針,msp和psp(不是游戲掌機(jī)!),在異常入口,EXC_RETURN的bit 2的值代表了激活的是哪一個(gè)SP指針,如果為1,那么是psp被激活,反之則是msp。
以下方代碼為例,

當(dāng)發(fā)生故障時(shí),在handler中我們可以查看棧的前八個(gè)值,它們是r0, r1, r2, r3, r12, LR, pc, xPSR,我們可以得到:

讓我們把目光放在LR和pc,我們就能知道是在程序的什么地方(illegal_instruction_execution中)以及具體執(zhí)行了什么命令(執(zhí)行0xE0000000地址的指令)。
當(dāng)然,實(shí)際在項(xiàng)目當(dāng)中我們調(diào)試過程倒不必這么麻煩,以Elektrobit AUTOSAR產(chǎn)品為例你能夠以一種更加直觀的方式獲取各種你需要的值。

故障中的故障!
我知道有人此時(shí)非常關(guān)心一個(gè)問題,要是在handler中處理故障時(shí),發(fā)生了一個(gè)新的故障,怎!么!辦!
其實(shí)上文也有提到,如果在使能了可配置故障handler的情況下,在其中產(chǎn)生了新的故障時(shí),會觸發(fā)HardFault。
一旦在HardFault之中,ARM Core運(yùn)行在一個(gè)不可配置優(yōu)先等級—— -1,此時(shí)一個(gè)新的故障會讓處理器進(jìn)入一個(gè)不可恢復(fù)的狀態(tài),且需要reset,這種狀態(tài)叫做Lockup。
不過,如果你是連接著調(diào)試器,Lockup在此時(shí)就不會導(dǎo)致reset。
?
自動恢復(fù)
可能你也感受到了,很多時(shí)候我們并不能精確地指出是何處的代碼發(fā)生問題,對于MCU來說可能使用reset是一種最簡單最無腦的恢復(fù)方式。不過對于如今的AUTOSAR程序來說,客戶爸爸會有更細(xì)化的需求,比如僅僅重置某一個(gè)應(yīng)用程序或者某一個(gè)應(yīng)用分區(qū)。
Anyway,作為AUTOSAR底層軟件,已經(jīng)提供了盡可能多的錯(cuò)誤信息,如何定制策略,以及如何單獨(dú)重置AUTOSAR應(yīng)用,本文不會涉及。
?
幾種典型的錯(cuò)誤
eXecute Never Fault

這段代碼上面已經(jīng)提及,如果嘗試執(zhí)行0xE0000000地址,會進(jìn)入HardFault。
讀取'壞'地址

如果嘗試從一個(gè)讀不到的地址獲取數(shù)據(jù)時(shí),會觸發(fā)Bus Fault。
協(xié)處理器故障

在我們沒有使能協(xié)處理器的情況下,使用類似于vmov(浮點(diǎn)指針指令)這樣的指令時(shí),會導(dǎo)致coprocessor fault。

執(zhí)行這段代碼,進(jìn)入異常并查看IMPRECISERR值時(shí),你會發(fā)現(xiàn)此時(shí)值為1,那么我們所獲取到的故障地址并不能確切代表實(shí)際導(dǎo)致故障的代碼。
那只好在所指地址附近看看有什么代碼可能會導(dǎo)致這個(gè)問題。
如果是M3或M4系列,你可以通過使能Auxiliary Control Register (ACTLR)的DISDEFWBUF bit位來禁止所有的寫入緩存操作,這樣你就可以避免IMPRECISERR為1的情況。—— 當(dāng)然,這個(gè)對性能是有影響的。
所以,對于M7架構(gòu)的S32G來說,無法做到強(qiáng)制所有存儲操作都是同步的,那么也就無法精確獲取故障地址了。
歡迎大家針對架構(gòu)更新或者Arm文檔更新評論留言進(jìn)行討論。
作者:

陳謙
Elektrobit中國團(tuán)隊(duì)的軟件工程師
專注于Classic AUTOSAR
Elektrobit 針對汽車 ECU 的 AUTOSAR 軟件產(chǎn)品和解決方案:
Elektrobit 經(jīng)典 AUTOSAR 基礎(chǔ)軟件、汽車操作系統(tǒng)和量身定制的工具環(huán)境:EB tresos www.elektrobit.cn/products/ecu/eb-tresos/
Elektrobit 用于打造高性能計(jì)算平臺(HPC)的自適應(yīng) AUTOSAR 基礎(chǔ)軟件、虛擬機(jī)監(jiān)控程序(Hypervisor)、車規(guī)級操作系統(tǒng)和集成式開發(fā)環(huán)境:EB corbos www.elektrobit.cn/products/ecu/eb-corbos/
Elektrobit 推出的業(yè)內(nèi)首款能夠?qū)崿F(xiàn)安全、高性能車載網(wǎng)絡(luò)通信的汽車以太網(wǎng)交換機(jī)固件:EB zoneo www.elektrobit.cn/products/ecu/eb-zoneo/
Elektrobit 為汽車電子控制單元(ECU)提供的嵌入式安全解決方案:EB zentur www.elektrobit.cn/products/security/
登入Elektrobit官網(wǎng)申請下載EB tresos免費(fèi)試用包,配置符合AUTOSA標(biāo)準(zhǔn)的軟件工程:https://www.elektrobit.cn/products-ecu-eb-tresos-evaluation-package/?