鴻蒙輕內(nèi)核M核源碼分析系列十八Fault異常處理
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
Fault異常處理模塊與OpenHarmony LiteOS-M內(nèi)核芯片架構(gòu)相關(guān),提供對HardFault、MemManage、BusFault、UsageFault等各種故障異常處理。有關(guān)Cortex-M芯片相關(guān)的知識不在本文討論,請自行參考《Cortex™-M7 Devices Generic User Guide》等官方資料。本文先簡單介紹下Fault異常類型,向量表及其代碼,異常處理C語言程序,然后詳細(xì)分析下異常處理匯編函數(shù)實(shí)現(xiàn)代碼。
1、Fault Type異常類型
如下圖中的Fault類型表格所示,F(xiàn)ault表示各種故障,Handler表示故障處理機(jī)制,Bit Name標(biāo)記故障的寄存器的Bit位,F(xiàn)ault status register故障狀態(tài)寄存器。該圖摘自《Cortex™-M7 Devices Generic User Guide》。


2、Vector table向量表
向量表包含棧指針的復(fù)位值和開始地址,也叫異常向量。異??梢钥醋魈厥獾闹袛啵惓>幪朎xception number, 中斷請求號IRQ number,偏移值offset,向量Vector的對應(yīng)關(guān)系如下圖所示,本文主要關(guān)注NMI、HardFault、Memory management fault、Bus fault、Usage fault、SVCall等異常。

在中斷初始化時(shí),會初始化該異常向量表,代碼位置kernel\arch\arm\cortex-m7\gcc\los_interrupt.c。⑴處的HalExcNMI,⑵處的HalExcHardFault,⑶處的HalExcMemFault,⑷處的HalExcBusFault,⑸處的HalExcUsageFault,⑹處的HalExcSvcCall這些中斷異常處理函數(shù)定義在kernel\arch\arm\cortex-m7\gcc\los_exc.S。本文我們主要分析這些匯編函數(shù)的代碼。
⑺處開始的這兩行代碼也比較重要,通過更改系統(tǒng)處理控制與狀態(tài)寄存器(System Handler Control and State Register)的bit位來使能相應(yīng)的異常,通過更改配置與控制寄存器(Configuration and Control Register)的bit位來使能除零異常。
- LITE_OS_SEC_TEXT_INIT VOID HalHwiInit(VOID)
- {
- #if (LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT == 1)
- UINT32 index;
- g_hwiForm[0] = 0; /* [0] Top of Stack */
- g_hwiForm[1] = Reset_Handler; /* [1] reset */
- for (index = 2; index < OS_VECTOR_CNT; index++) { /* 2: The starting position of the interrupt */
- g_hwiForm[index] = (HWI_PROC_FUNC)HalHwiDefaultHandler;
- }
- /* Exception handler register */
- ⑴ g_hwiForm[NonMaskableInt_IRQn + OS_SYS_VECTOR_CNT] = HalExcNMI;
- ⑵ g_hwiForm[HARDFAULT_IRQN + OS_SYS_VECTOR_CNT] = HalExcHardFault;
- ⑶ g_hwiForm[MemoryManagement_IRQn + OS_SYS_VECTOR_CNT] = HalExcMemFault;
- ⑷ g_hwiForm[BusFault_IRQn + OS_SYS_VECTOR_CNT] = HalExcBusFault;
- ⑸ g_hwiForm[UsageFault_IRQn + OS_SYS_VECTOR_CNT] = HalExcUsageFault;
- ⑹ g_hwiForm[SVCall_IRQn + OS_SYS_VECTOR_CNT] = HalExcSvcCall;
- g_hwiForm[PendSV_IRQn + OS_SYS_VECTOR_CNT] = HalPendSV;
- g_hwiForm[SysTick_IRQn + OS_SYS_VECTOR_CNT] = SysTick_Handler;
- /* Interrupt vector table location */
- SCB->VTOR = (UINT32)(UINTPTR)g_hwiForm;
- #endif
- #if (__CORTEX_M >= 0x03U) /* only for Cortex-M3 and above */
- NVIC_SetPriorityGrouping(OS_NVIC_AIRCR_PRIGROUP);
- #endif
- /* Enable USGFAULT, BUSFAULT, MEMFAULT */
- ⑺ *(volatile UINT32 *)OS_NVIC_SHCSR |= (USGFAULT | BUSFAULT | MEMFAULT);
- /* Enable DIV 0 and unaligned exception */
- *(volatile UINT32 *)OS_NVIC_CCR |= DIV0FAULT;
- return;
- }
3、HalExcHandleEntry異常處理C程序入口
HalExcHandleEntry異常處理函數(shù)是匯編異常函數(shù)跳轉(zhuǎn)到C語言程序的入口,定義在文件kernel\arch\arm\cortex-m7\gcc\los_interrupt.c,被kernel\arch\arm\cortex-m7\gcc\los_exc.S文件中的匯編函數(shù)調(diào)用。函數(shù)參數(shù)由匯編程序中的R0-R3寄存器傳值進(jìn)來,匯編程序中的寄存器和HalExcHandleEntry函數(shù)參數(shù)對應(yīng)關(guān)系如下表所示:
下面我們分析下函數(shù)的源代碼,⑴處的標(biāo)簽表示異常類型參數(shù)的高16位用于特色的標(biāo)記,主要用于標(biāo)記故障地址是否有效、是否故障發(fā)生在中斷中,是否支持浮點(diǎn)等。⑵處增加中斷計(jì)數(shù)和嵌套異常數(shù)目。⑶記錄異常類型,⑷處如果記錄了有效的故障地址,則獲取故障地址。⑸處如果當(dāng)前運(yùn)行任務(wù)存在時(shí),若標(biāo)記了異常發(fā)生在中斷,則記錄中斷號,并記錄異常發(fā)生在中斷內(nèi),否則記錄任務(wù)編號,并記錄異常發(fā)生在任務(wù)內(nèi)。如果當(dāng)前運(yùn)行任務(wù)為空,則異常發(fā)生在初始化階段。⑹處如果異常類型里包含支持浮點(diǎn)數(shù)的標(biāo)記,則相應(yīng)處理下。⑺處輸出異常信息到控制臺。
- LITE_OS_SEC_TEXT_INIT VOID HalExcHandleEntry(UINT32 excType, UINT32 faultAddr, UINT32 pid, EXC_CONTEXT_S *excBufAddr)
- {
- ⑴ UINT16 tmpFlag = (excType >> 16) & OS_NULL_SHORT; /* 16: Get Exception Type */
- ⑵ g_intCount++;
- g_excInfo.nestCnt++;
- ⑶ g_excInfo.type = excType & OS_NULL_SHORT;
- ⑷ if (tmpFlag & OS_EXC_FLAG_FAULTADDR_VALID) {
- g_excInfo.faultAddr = faultAddr;
- } else {
- g_excInfo.faultAddr = OS_EXC_IMPRECISE_ACCESS_ADDR;
- }
- ⑸ if (g_losTask.runTask != NULL) {
- if (tmpFlag & OS_EXC_FLAG_IN_HWI) {
- g_excInfo.phase = OS_EXC_IN_HWI;
- g_excInfo.thrdPid = pid;
- } else {
- g_excInfo.phase = OS_EXC_IN_TASK;
- g_excInfo.thrdPid = g_losTask.runTask->taskID;
- }
- } else {
- g_excInfo.phase = OS_EXC_IN_INIT;
- g_excInfo.thrdPid = OS_NULL_INT;
- }
- ⑹ if (excType & OS_EXC_FLAG_NO_FLOAT) {
- g_excInfo.context = (EXC_CONTEXT_S *)((CHAR *)excBufAddr - LOS_OFF_SET_OF(EXC_CONTEXT_S, uwR4));
- } else {
- g_excInfo.context = excBufAddr;
- }
- ⑺ OsDoExcHook(EXC_INTERRUPT);
- OsExcInfoDisplay(&g_excInfo);
- HalSysExit();
- }
4、Los_Exc異常處理匯編函數(shù)
上文介紹Vector table向量表時(shí),已經(jīng)提到了在文件kernel\arch\arm\cortex-m7\gcc\los_exc.S中定義的的異常處理函數(shù),如下。當(dāng)發(fā)生Fault故障異常時(shí),會調(diào)度執(zhí)行這些異常處理函數(shù),本節(jié)會詳細(xì)分析函數(shù)的源代碼來掌握內(nèi)核如何處理這些發(fā)生的異常。這6個(gè)函數(shù)處理過程類似,我們選擇2個(gè)典型的函數(shù)進(jìn)行分析。
- .global HalExcNMI
- .global HalExcHardFault
- .global HalExcMemFault
- .global HalExcBusFault
- .global HalExcUsageFault
- .global HalExcSvcCall
4.1 HalExcNMI
當(dāng)發(fā)生NMI(Non Maskable Interrupt,不可屏蔽中斷)時(shí),會觸發(fā)運(yùn)行HalExcNMI匯編函數(shù),該函數(shù)的執(zhí)行流程如下圖。下文會結(jié)合該流程圖來閱讀函數(shù)代碼。

HalExcNMI函數(shù)代碼如下,⑴處給R0寄存器賦值OS_EXC_CAUSE_NMI,該值等于16,對應(yīng)文件kernel\arch\arm\cortex-m7\gcc\los_arch_interrupt.h中的異常類型宏定義OS_EXC_CAUSE_NMI,均為16。該值對應(yīng)HalExcHandleEntry函數(shù)的第一個(gè)參數(shù)。⑵處設(shè)置故障地址,該值對應(yīng)HalExcHandleEntry函數(shù)的第二個(gè)參數(shù)。⑶處跳轉(zhuǎn)到函數(shù)osExcDispatch繼續(xù)執(zhí)行。
- .type HalExcNMI, %function
- .global HalExcNMI
- HalExcNMI:
- .fnstart
- .cantunwind
- ⑴ MOV R0, #OS_EXC_CAUSE_NMI
- ⑵ MOV R1, #0
- ⑶ B osExcDispatch
- .fnend
下面分析的一些函數(shù)比較通用,其他異常處理函數(shù)也都會調(diào)用。
4.1.1 osExcDispatch函數(shù)
osExcDispatch函數(shù)代碼如下,⑴處加載Interrupt Active Bit Registers中斷活躍位寄存器基地址。中斷活躍位寄存器共有8個(gè),NVIC_IABR0-NVIC_IABR7,每個(gè)寄存器包含32位,可以對應(yīng)32個(gè)中斷號,共支持256個(gè)中斷。其中,IABR[0]的 bit位0~31 分別對應(yīng)中斷號031;`IABR[1]`的bit位031對應(yīng)中斷32~63;其他以此類推。⑵處設(shè)置循環(huán)計(jì)數(shù),對應(yīng)8個(gè)寄存器,后文會循環(huán)遍歷8個(gè)寄存器查詢是否存在活躍的中斷。
- .type osExcDispatch, %function
- .global osExcDispatch
- osExcDispatch:
- .fnstart
- .cantunwind
- ⑴ LDR R2, =OS_NVIC_ACT_BASE
- ⑵ MOV R12, #8 // R12 is hwi check loop counter
- .fnend
4.1.2 _hwiActiveCheck函數(shù)
執(zhí)行完上述osExcDispatch函數(shù)代碼后,會繼續(xù)執(zhí)行隨后的函數(shù)_hwiActiveCheck的代碼。⑴處讀取活躍位寄存器的數(shù)值,然后執(zhí)行⑵比較寄存器數(shù)值與0的大小,如果相等,說明該活躍位寄存器對應(yīng)的中斷均不活躍,然后跳轉(zhuǎn)到_hwiActiveCheckNext。如果不等于0,則執(zhí)行⑶,參數(shù)類型的高16位標(biāo)記為中斷。⑷處代碼根據(jù)中斷活躍位計(jì)算中斷號,并賦值給寄存器R2,該值對應(yīng)HalExcHandleEntry函數(shù)的第三個(gè)參數(shù)。具體計(jì)算方式為,首先反轉(zhuǎn)活躍中斷位寄存器數(shù)值R3,并保存到R2,然后計(jì)算高位0的數(shù)量。把計(jì)數(shù)值R12加1,然后左移5位(等于乘以32),然后加上R2,就是中斷號。
- .type _hwiActiveCheck, %function
- .global _hwiActiveCheck
- _hwiActiveCheck:
- .fnstart
- .cantunwind
- ⑴ LDR R3, [R2] // R3 store active hwi register when exc
- ⑵ CMP R3, #0
- BEQ _hwiActiveCheckNext
- // exc occurred in IRQ
- ⑶ ORR R0, R0, #FLAG_HWI_ACTIVE
- ⑷ RBIT R2, R3
- CLZ R2, R2
- AND R12, R12, #1
- ADD R2, R2, R12, LSL #5 // calculate R2 (hwi number) as pid
- .fnend
4.1.3 _ExcInMSP函數(shù)和_NoFloatInMsp函數(shù)
如果有活躍的中斷,則繼續(xù)執(zhí)行后續(xù)的代碼。處理中斷時(shí),使用的主棧處理函數(shù)_ExcInMSP。⑴處比較異常返回值和#0XFFFFFFED的大小,如果相等說明支持浮點(diǎn)計(jì)算則繼續(xù)執(zhí)行后續(xù)代碼,如果不相等則不支持浮點(diǎn)計(jì)算,會跳轉(zhuǎn)到函數(shù)_NoFloatInMsp函數(shù)。有關(guān)異常返回值的更多信息請參考《Cortex™-M7 Devices Generic User Guide》表格Table 2-15 Exception return behavior。
如果支持浮點(diǎn)計(jì)算時(shí),執(zhí)行⑵把棧指針加上104賦值給R3寄存器,然后壓棧,該值對應(yīng)HalExcHandleEntry函數(shù)的第四個(gè)參數(shù)。104的大小應(yīng)該來源于結(jié)構(gòu)體EXC_CONTEXT_S。⑶處把寄存器PRIMASK數(shù)值復(fù)制到R12寄存器,然后把R4-R12寄存器壓棧。⑷處把浮點(diǎn)寄存器壓棧,⑸處跳轉(zhuǎn)到函數(shù)_handleEntry。
當(dāng)不支持浮點(diǎn)計(jì)算時(shí),執(zhí)行函數(shù)_NoFloatInMsp。⑹處把棧指針加上32賦值給R3寄存器,然后壓棧,該值對應(yīng)HalExcHandleEntry函數(shù)的第四個(gè)參數(shù)。然后把R3壓棧,把寄存器PRIMASK數(shù)值復(fù)制到R12,然后壓棧R4-R12。和支持浮點(diǎn)時(shí)的差別就是,不需要壓棧D8-D15寄存器。⑺處把參數(shù)類型高位上加上不支持浮點(diǎn)的標(biāo)記,然后跳轉(zhuǎn)到函數(shù)_handleEntry。
- .type _ExcInMSP, %function
- .global _ExcInMSP
- _ExcInMSP:
- .fnstart
- .cantunwind
- ⑴ CMP LR, #0XFFFFFFED
- BNE _NoFloatInMsp
- ⑵ ADD R3, R13, #104
- PUSH {R3}
- ⑶ MRS R12, PRIMASK // store message-->exc: disable int?
- PUSH {R4-R12} // store message-->exc: {R4-R12}
- #if ((defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \
- (defined(__FPU_USED) && (__FPU_USED == 1U)))
- ⑷ VPUSH {D8-D15}
- #endif
- ⑸ B _handleEntry
- .fnend
- .type _NoFloatInMsp, %function
- .global _NoFloatInMsp
- _NoFloatInMsp:
- .fnstart
- .cantunwind
- ⑹ ADD R3, R13, #32
- PUSH {R3} // save IRQ SP // store message-->exc: MSP(R13)
- MRS R12, PRIMASK // store message-->exc: disable int?
- PUSH {R4-R12} // store message-->exc: {R4-R12}
- ⑺ ORR R0, R0, #FLAG_NO_FLOAT
- B _handleEntry
- .fnend
4.1.4 _hwiActiveCheckNext函數(shù)
遍歷中斷活躍位寄存器時(shí),如果前一個(gè)寄存器沒有活躍的中斷則執(zhí)行函數(shù)_hwiActiveCheckNext判斷下一個(gè)寄存器是否有活躍的中斷。⑴處把活躍位寄存器地址偏移4字節(jié),計(jì)數(shù)減1,如果還有其他活躍位寄存器,則跳轉(zhuǎn)到函數(shù)_hwiActiveCheck繼續(xù)判斷。否則執(zhí)行后續(xù)的代碼,⑵處加載System Handler Control and State Register(縮寫SHCSRS)系統(tǒng)處理控制與狀態(tài)寄存器的地址,然后加載半字節(jié)數(shù)值。⑶處加載掩碼0xC00,該數(shù)值二進(jìn)制的第10、第11位為1。SHCSRS寄存器的第11位對應(yīng)SysTick異?;钴S位,第10位對應(yīng)PendSV異?;钴S位。⑷處R2、R3進(jìn)行邏輯與計(jì)算,然后把結(jié)果與0進(jìn)行比較,如果結(jié)果為0,說明沒有發(fā)生ysTick異?;騊endSV異常。如果結(jié)果為1,說明發(fā)生了異常,需要執(zhí)行⑸跳轉(zhuǎn)到函數(shù)_ExcInMSP繼續(xù)執(zhí)行,上文已分析該函數(shù)。⑹處獲取全局變量g_taskScheduled的地址,然后獲取其數(shù)值,與1進(jìn)行比較。如果等于1,說明系統(tǒng)已經(jīng)開始任務(wù)調(diào)度,會繼續(xù)執(zhí)行后續(xù)的代碼。如果不為1,系統(tǒng)未調(diào)度,處于初始化階段,需要跳轉(zhuǎn)到函數(shù)_ExcInMSP繼續(xù)執(zhí)行。
如果系統(tǒng)開始了任務(wù)調(diào)度,此時(shí)使用進(jìn)程棧PSP,執(zhí)行⑺,判斷系統(tǒng)是否支持浮點(diǎn)計(jì)算。如果支持則繼續(xù)執(zhí)行,否則跳轉(zhuǎn)到函數(shù)_NoFloatInPsp。⑻處開始的代碼和函數(shù)_NoFloatInPsp可以對比著閱讀,前者需要壓棧浮點(diǎn)寄存器,后者不需要。⑻處把棧指針復(fù)制到R2寄存器,然后把棧指針減去96。⑼處把PSP線程棧指針值賦值給R3寄存器,然后把R3加104賦值給寄存器R12,計(jì)算出來的值是任務(wù)棧指針,然后進(jìn)行壓棧。
⑽處復(fù)制PRIMASK寄存器數(shù)值到R12,然后把寄存器R4-R12壓棧,接著壓棧浮點(diǎn)寄存器D8-D15。⑾處從PSP棧指針開始把R4-R11、D8-D15出棧,然后從R13棧指針開始把D8-D15、R4-R11進(jìn)行壓棧。⑿處跳轉(zhuǎn)到函數(shù)_handleEntry繼續(xù)指向。
- .type _hwiActiveCheckNext, %function
- .global _hwiActiveCheckNext
- _hwiActiveCheckNext:
- .fnstart
- .cantunwind
- ⑴ ADD R2, R2, #4 // next NVIC ACT ADDR
- SUBS R12, R12, #1
- BNE _hwiActiveCheck
- /*NMI interrupt exception*/
- ⑵ LDR R2, =OS_NVIC_SHCSRS
- LDRH R2,[R2]
- ⑶ LDR R3,=OS_NVIC_SHCSR_MASK
- ⑷ AND R2, R2,R3
- CMP R2,#0
- ⑸ BNE _ExcInMSP
- // exc occured in Task or Init or exc
- // reserved for register info from task stack
- ⑹ LDR R2, =g_taskScheduled
- LDR R2, [R2]
- TST R2, #1 // OS_FLG_BGD_ACTIVE
- BEQ _ExcInMSP // if exc occurred in Init then branch
- ⑺ CMP LR, #0xFFFFFFED //auto push floating registers
- BNE _NoFloatInPsp
- // exc occurred in Task
- ⑻ MOV R2, R13
- SUB R13, #96 // add 8 Bytes reg(for STMFD)
- ⑼ MRS R3, PSP
- ADD R12, R3, #104
- PUSH {R12} // save task SP
- ⑽ MRS R12, PRIMASK
- PUSH {R4-R12}
- VPUSH {D8-D15}
- // copy auto saved task register
- ⑾ LDMFD R3!, {R4-R11} // R4-R11 store PSP reg(auto push when exc in task)
- VLDMIA R3!, {D8-D15}
- VSTMDB R2!, {D8-D15}
- STMFD R2!, {R4-R11}
- ⑿ B _handleEntry
- .fnend
- .type _NoFloatInPsp, %function
- .global _NoFloatInPsp
- _NoFloatInPsp:
- .fnstart
- .cantunwind
- MOV R2, R13 // no auto push floating registers
- SUB R13, #32 // add 8 Bytes reg(for STMFD)
- MRS R3, PSP
- ADD R12, R3, #32
- PUSH {R12} // save task SP
- MRS R12, PRIMASK
- PUSH {R4-R12}
- LDMFD R3, {R4-R11} // R4-R11 store PSP reg(auto push when exc in task)
- STMFD R2!, {R4-R11}
- ORR R0, R0, #FLAG_NO_FLOAT
- .fnend
4.1.5 _handleEntry函數(shù)
繼續(xù)分析函數(shù)_handleEntry。代碼很簡單,⑴把棧指針復(fù)制給R3,該值對應(yīng)HalExcHandleEntry函數(shù)的第四個(gè)參數(shù)。⑵處關(guān)閉中斷,關(guān)閉Fault異常,然后執(zhí)行⑵跳轉(zhuǎn)到C語言的函數(shù)HalExcHandleEntry。
- _handleEntry:
- .fnstart
- .cantunwind
- ⑴ MOV R3, R13 // R13:the 4th param
- ⑵ CPSID I
- CPSID F
- B HalExcHandleEntry
- NOP
- .fnend
4.2 HalExcUsageFault
當(dāng)發(fā)生使用異常UsageFault時(shí),會觸發(fā)運(yùn)行HalExcUsageFault匯編函數(shù),該函數(shù)的執(zhí)行流程如下圖。下文會結(jié)合該流程圖來閱讀函數(shù)代碼。

HalExcUsageFault函數(shù)代碼如下,⑴處把可配置故障狀態(tài)寄存器Configurable Fault Status Register(CFSR)的地址復(fù)制到R0寄存器,然后讀取寄存器值到R0寄存器。⑵處把0x030F賦值給R1寄存器,然后左移16位。UsageFault Status Register使用故障狀態(tài)寄存器的有效性如下,即0-3,8-9為有效位,0x030F的二進(jìn)制對應(yīng)這些有效位。⑶處進(jìn)行邏輯與,這樣就計(jì)算出實(shí)際的使用故障對應(yīng)的bit位。⑷處把R12賦值為0,然后會繼續(xù)執(zhí)行后續(xù)的匯編代碼osExcCommonBMU。

- .type HalExcUsageFault, %function
- .global HalExcUsageFault
- HalExcUsageFault:
- .fnstart
- .cantunwind
- ⑴ LDR R0, =OS_NVIC_FSR
- LDR R0, [R0]
- ⑵ MOVW R1, #0x030F
- LSL R1, R1, #16
- ⑶ AND R0, R0, R1
- ⑷ MOV R12, #0
- .fnend
4.2.1 g_uwExcTbl數(shù)組
在看osExcCommonBMU函數(shù)的代碼之前需要了解下g_uwExcTbl數(shù)組,g_uwExcTbl數(shù)組定義在文件kernel\arch\arm\cortex-m7\gcc\los_interrupt.c,代碼如下。
該數(shù)組包含32個(gè)元素,每個(gè)元素對應(yīng)CFSR寄存器的一個(gè)bit位,元素?cái)?shù)值在LiteOS-M中定義為異常類型。比如OS_EXC_UF_DIVBYZERO等于異常類型10,為除零異常。
- UINT8 g_uwExcTbl[FAULT_STATUS_REG_BIT] = {
- 0, 0, 0, 0, 0, 0, OS_EXC_UF_DIVBYZERO, OS_EXC_UF_UNALIGNED,
- 0, 0, 0, 0, OS_EXC_UF_NOCP, OS_EXC_UF_INVPC, OS_EXC_UF_INVSTATE, OS_EXC_UF_UNDEFINSTR,
- 0, 0, 0, OS_EXC_BF_STKERR, OS_EXC_BF_UNSTKERR, OS_EXC_BF_IMPRECISERR, OS_EXC_BF_PRECISERR, OS_EXC_BF_IBUSERR,
- 0, 0, 0, OS_EXC_MF_MSTKERR, OS_EXC_MF_MUNSTKERR, 0, OS_EXC_MF_DACCVIOL, OS_EXC_MF_IACCVIOL
- };
4.2.2 osExcCommonBMU函數(shù)
現(xiàn)在來分析下匯編代碼osExcCommonBMU。⑴處計(jì)算出R0數(shù)值的高位0的個(gè)數(shù),加載數(shù)組全局變量g_uwExcTbl地址到R3寄存器,然后執(zhí)行⑵計(jì)算是第幾個(gè)數(shù)組元素,加載元素值到R0寄存器。⑶處R0與R12進(jìn)行邏輯或運(yùn)算,沒有什么影響。R0對應(yīng)HalExcHandleEntry函數(shù)的第一個(gè)參數(shù)。后續(xù)會繼續(xù)執(zhí)行osExcDispatch函數(shù),前文已經(jīng)分析過。
- .type osExcCommonBMU, %function
- .global osExcCommonBMU
- osExcCommonBMU:
- .fnstart
- .cantunwind
- ⑴ CLZ R0, R0
- LDR R3, =g_uwExcTbl
- ⑵ ADD R3, R3, R0
- LDRB R0, [R3]
- ⑶ ORR R0, R0, R12
- .fnend
小結(jié)
本文介紹了Fault異常類型,向量表及其代碼,異常處理C語言程序,異常處理匯編函數(shù)實(shí)現(xiàn)代碼。
文章相關(guān)附件可以點(diǎn)擊下面的原文鏈接前往下載
https://harmonyos.51cto.com/resource/1344
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)


























