中斷Hwi:提高鴻蒙輕內核系統實時性及執行效率的祕密武器

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​​​​​​​​摘要:本文帶領大家一起剖析了鴻蒙輕內核的中斷模塊的源代碼,掌握中斷相關的概念,中斷初始化操作,中斷創建、刪除,開關中斷操作等。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文分享自華爲雲社區","attrs":{}},{"type":"link","attrs":{"href":"https://bbs.huaweicloud.com/blogs/273320?utm_source=infoq&utm_medium=bbs-ex&utm_campaign=iot&utm_content=content","title":"","type":null},"content":[{"type":"text","text":"《鴻蒙輕內核M核源碼分析系列五 中斷Hwi》","attrs":{}}]},{"type":"text","text":",原文作者:zhushy。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文,我們講述一下中斷,會給讀者介紹中斷的概念,鴻蒙輕內核的中斷模塊的源代碼。本文中所涉及的源碼,以OpenHarmony LiteOS-M內核爲例,均可以在開源站點","attrs":{}},{"type":"link","attrs":{"href":"https://gitee.com/openharmony/kernel_liteos_m","title":"","type":null},"content":[{"type":"text","text":"https://gitee.com/openharmony/kernel_liteos_m","attrs":{}}]},{"type":"text","text":" 獲取。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"1、中斷概念介紹","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷是指出現需要時,CPU暫停執行當前程序,轉而執行新程序的過程。當外設需要CPU時,將通過產生中斷信號使CPU立即中斷當前任務來響應中斷請求。在剖析中斷源代碼之前,下面介紹些中斷相關的硬件、中斷相關的概念。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1.1 中斷相關的硬件介紹","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與中斷相關的硬件可以劃分爲三類:設備、中斷控制器、CPU本身。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設備","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"發起中斷的源,當設備需要請求CPU時,產生一箇中斷信號,該信號連接至中斷控制器。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷控制器","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷控制器是CPU衆多外設中的一個,它一方面接收其它外設中斷引腳的輸入。另一方面,它會發出中斷信號給CPU。可以通過對中斷控制器編程來打開和關閉中斷源、設置中斷源的優先級和觸發方式。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"CPU","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"CPU會響應中斷源的請求,中斷當前正在執行的任務,轉而執行中斷處理程序。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1.2 中斷相關的概念","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷號","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每個中斷請求信號都會有特定的標誌,使得計算機能夠判斷是哪個設備提出的中斷請求,這個標誌就是中斷號。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷優先級","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲使系統能夠及時響應並處理所有中斷,系統根據中斷時間的重要性和緊迫程度,將中斷源分爲若干個級別,稱作中斷優先級。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷處理程序","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當外設產生中斷請求後,CPU暫停當前的任務,轉而響應中斷申請,即執行中斷處理程序。產生中斷的每個設備都有相應的中斷處理程序。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷向量","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷服務程序的入口地址。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷向量表","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"存儲中斷向量的存儲區,中斷向量與中斷號對應,中斷向量在中斷向量表中按照中斷號順序存儲。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷共享","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當外設較少時,可以實現一個外設對應一箇中斷號,但爲了支持更多的硬件設備,可以讓多個設備共享一箇中斷號,共享同一個中斷號的中斷處理程序形成一個鏈表。當外部設備產生中斷申請時,系統會遍歷中斷號對應的中斷處理程序鏈表,直到找到對應設備的中斷處理程序。在遍歷執行過程中,各中斷處理程序可以通過檢測設備ID,判斷是否是這個中斷處理程序對應的設備產生的中斷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,我們再看看鴻蒙輕內核中斷源代碼。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"2、鴻蒙輕內核中斷源代碼","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.1 中斷相關的聲明和定義","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在文件kernel\\arch\\arm\\cortex-m7\\gcc\\los_interrupt.c中定義了一些結構體、全局變量、內聯函數,在分析源碼之前,我們先看下這些定義和聲明。全部變量g_intCount表示正在處理的中斷數量,每次進入中斷處理程序時,都會把該變量數值加1,完成中斷處理退出時,該數值減1。對應的內聯函數HalIsIntActive()用於獲取是否正在處理中斷,返回值大於0,則表示正在處理中斷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"UINT32 g_intCount = 0;\n\ninline UINT32 HalIsIntActive(VOID)\n{\n return (g_intCount > 0);\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​我們在再看看中斷向量表定義。⑴處代碼爲系統支持的中斷定義了數組g_hwiForm[OS_VECTOR_CNT],對於每一箇中斷號hwiNum,對應的數組元素g_hwiForm[hwiNum]表示每一箇中斷對應的中斷處理執行入口程序。⑵處的宏OS_HWI_WITH_ARG表示中斷處理程序是否支持參數傳入,默認關閉。如果支持傳參,定義⑶處的結構體HWI_HANDLER_FUNC來維護中斷處理函數及其參數,還需要定義⑷處g_hwiHandlerForm數組。如果不支持傳參,使用⑹處定義的g_hwiHandlerForm數組。對於每一箇中斷號hwiNum,對應的數組元素g_hwiHandlerForm[hwiNum]表示每一箇中斷對應的中斷處理程序。⑸、⑺處定義個函數OsSetVector()用於設置指定中斷號對應的中斷處理執行入口程序和中斷處理程序。中斷處理執行入口程序和中斷處理程序的關係是,當中斷髮生時,會執行中斷處理執行入口程序,這個函數會進一步調用中斷處理程序。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"⑴ STATIC HWI_PROC_FUNC __attribute__((aligned(0x100))) g_hwiForm[OS_VECTOR_CNT] = {0};\n\n⑵ #if (OS_HWI_WITH_ARG == 1)\n\n⑶ typedef struct {\n HWI_PROC_FUNC pfnHandler;\n VOID *pParm;\n } HWI_HANDLER_FUNC;\n\n⑷ STATIC HWI_HANDLER_FUNC g_hwiHandlerForm[OS_VECTOR_CNT] = {{ (HWI_PROC_FUNC)0, (HWI_ARG_T)0 }};\n⑸ VOID OsSetVector(UINT32 num, HWI_PROC_FUNC vector, VOID *arg)\n {\n if ((num + OS_SYS_VECTOR_CNT) < OS_VECTOR_CNT) {\n g_hwiForm[num + OS_SYS_VECTOR_CNT] = (HWI_PROC_FUNC)HalInterrupt;\n g_hwiHandlerForm[num + OS_SYS_VECTOR_CNT].pfnHandler = vector;\n g_hwiHandlerForm[num + OS_SYS_VECTOR_CNT].pParm = arg;\n }\n }\n\n #else\n\n⑹ STATIC HWI_PROC_FUNC g_hwiHandlerForm[OS_VECTOR_CNT] = {0};\n\n⑺ VOID OsSetVector(UINT32 num, HWI_PROC_FUNC vector)\n {\n if ((num + OS_SYS_VECTOR_CNT) < OS_VECTOR_CNT) {\n g_hwiForm[num + OS_SYS_VECTOR_CNT] = HalInterrupt;\n g_hwiHandlerForm[num + OS_SYS_VECTOR_CNT] = vector;\n }\n }\n #endif","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.2 中斷初始化HalHwiInit()","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在系統啓動時,在kernel\\src\\los_init.c中調用HalArchInit()進行中斷初始化。這個函數定義在kernel\\arch\\arm\\cortex-m7\\gcc\\los_context.c,然後進一步調用定義在kernel\\arch\\arm\\cortex-m7\\gcc\\los_interrupt.c文件中HalHwiInit()函數完成中斷向量初始化。我們分析下代碼。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"宏LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT表示是否使用系統預定義的向量基地址和中斷處理程序,默認開啓。⑴處開始,中斷向量表的0號中斷設置爲空,1號中斷對應復位處理程序Reset_Handler。⑵處把其餘的中斷設置爲默認的中斷處理執行入口程序HalHwiDefaultHandler()。⑶處設置系統中斷(異常是中斷的一種,系統中斷也稱爲異常),系統中斷的執行入口函數定義在kernel\\arch\\arm\\cortex-m7\\gcc\\los_exc.S,使用匯編語言實現。系統中斷中,14號中斷對應HalPendSV處理程序,用於任務上下文切換,15號中斷是tick中斷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"執行⑷處代碼把中斷向量表賦值給SCB->VTOR。對於Cortex-M3及以上的CPU核,還需要執行⑸設置優先級組。⑹處代碼使能指定的異常。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"LITE_OS_SEC_TEXT_INIT VOID HalHwiInit()\n{\n#if (LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT == 1)\n UINT32 index;\n⑴ g_hwiForm[0] = 0; /* [0] Top of Stack */\n g_hwiForm[1] = Reset_Handler; /* [1] reset */\n⑵ for (index = 2; index < OS_VECTOR_CNT; index++) { /* 2: The starting position of the interrupt */\n g_hwiForm[index] = (HWI_PROC_FUNC)HalHwiDefaultHandler;\n }\n /* Exception handler register */\n⑶ g_hwiForm[NonMaskableInt_IRQn + OS_SYS_VECTOR_CNT] = HalExcNMI;\n g_hwiForm[HARDFAULT_IRQN + OS_SYS_VECTOR_CNT] = HalExcHardFault;\n g_hwiForm[MemoryManagement_IRQn + OS_SYS_VECTOR_CNT] = HalExcMemFault;\n g_hwiForm[BusFault_IRQn + OS_SYS_VECTOR_CNT] = HalExcBusFault;\n g_hwiForm[UsageFault_IRQn + OS_SYS_VECTOR_CNT] = HalExcUsageFault;\n g_hwiForm[SVCall_IRQn + OS_SYS_VECTOR_CNT] = HalExcSvcCall;\n g_hwiForm[PendSV_IRQn + OS_SYS_VECTOR_CNT] = HalPendSV;\n g_hwiForm[SysTick_IRQn + OS_SYS_VECTOR_CNT] = SysTick_Handler;\n\n /* Interrupt vector table location */\n⑷ SCB->VTOR = (UINT32)(UINTPTR)g_hwiForm;\n#endif\n#if (__CORTEX_M >= 0x03U) /* only for Cortex-M3 and above */\n⑸ NVIC_SetPriorityGrouping(OS_NVIC_AIRCR_PRIGROUP);\n#endif\n\n /* Enable USGFAULT, BUSFAULT, MEMFAULT */\n⑹ *(volatile UINT32 *)OS_NVIC_SHCSR |= (USGFAULT | BUSFAULT | MEMFAULT);\n /* Enable DIV 0 and unaligned exception */\n *(volatile UINT32 *)OS_NVIC_CCR |= DIV0FAULT;\n\n return;\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.3 創建中斷UINT32 HalHwiCreate()","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開發者可以調用函數UINT32HalHwiCreate()創建中斷,註冊中斷處理程序。我們先看看這個函數的參數,HWI_HANDLE_T hwiNum是硬件中斷號,HWI_PRIOR_ThwiPrio中斷的優先級,HWI_MODE_T mode中斷模式,保留暫時沒有使用。HWI_PROC_FUNC handler是需要註冊的中斷處理程序,中斷被觸發後會調用這個函數。HWI_ARG_T arg是中斷處理程序的參數。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一起剖析下這個函數的源代碼,⑴處代碼開始,對入參進行校驗,中斷處理程序不能爲空,中斷號不能大於支持的最大中斷號,中斷優先級不能超過指定優先級的大小。如果待創建的中斷號對應的中斷執行入口程序不等於HalHwiDefaultHandler,說明已經創建過,返回錯誤碼。關中斷,然後執行⑵處的OsSetVector()函數設置指定中斷號的中斷處理程序。⑶處調用CMSIS函數使能中斷、設置中斷的優先級,打開中斷,完成中斷的創建。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"LITE_OS_SEC_TEXT_INIT UINT32 HalHwiCreate(HWI_HANDLE_T hwiNum,\n HWI_PRIOR_T hwiPrio,\n HWI_MODE_T mode,\n HWI_PROC_FUNC handler,\n HWI_ARG_T arg)\n{\n UINTPTR intSave;\n\n⑴ if (handler == NULL) {\n return OS_ERRNO_HWI_PROC_FUNC_NULL;\n }\n\n if (hwiNum >= OS_HWI_MAX_NUM) {\n return OS_ERRNO_HWI_NUM_INVALID;\n }\n\n if (g_hwiForm[hwiNum + OS_SYS_VECTOR_CNT] != (HWI_PROC_FUNC)HalHwiDefaultHandler) {\n return OS_ERRNO_HWI_ALREADY_CREATED;\n }\n\n if (hwiPrio > OS_HWI_PRIO_LOWEST) {\n return OS_ERRNO_HWI_PRIO_INVALID;\n }\n\n intSave = LOS_IntLock();\n#if (OS_HWI_WITH_ARG == 1)\n OsSetVector(hwiNum, handler, arg);\n#else\n⑵ OsSetVector(hwiNum, handler);\n#endif\n⑶ NVIC_EnableIRQ((IRQn_Type)hwiNum);\n NVIC_SetPriority((IRQn_Type)hwiNum, hwiPrio);\n\n LOS_IntRestore(intSave);\n\n return LOS_OK;\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.4 刪除中斷UINT32 HalHwiDelete()","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"中斷刪除操作是創建操作的反向操作,也比較好理解。開發者可以調用函數UINT32 HalHwiDelete(HWI_HANDLE_T hwiNum)來刪除中斷。函數需要指定中斷號參數HWI_HANDLE_T hwiNum。一起剖析下這個函數的源代碼,⑴處代碼對入參進行校驗,不能大於支持的最大中斷號。⑵處調用CMSIS函數來失能中斷,然後鎖中斷,執行⑶把中斷向量表指定中斷號的中斷執行入口程序設置爲默認程序HalHwiDefaultHandler。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"LITE_OS_SEC_TEXT_INIT UINT32 HalHwiDelete(HWI_HANDLE_T hwiNum)\n{\n UINT32 intSave;\n\n⑴ if (hwiNum >= OS_HWI_MAX_NUM) {\n return OS_ERRNO_HWI_NUM_INVALID;\n }\n\n⑵ NVIC_DisableIRQ((IRQn_Type)hwiNum);\n\n intSave = LOS_IntLock();\n\n⑶ g_hwiForm[hwiNum + OS_SYS_VECTOR_CNT] = (HWI_PROC_FUNC)HalHwiDefaultHandler;\n\n LOS_IntRestore(intSave);\n\n return LOS_OK;\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.5 中斷處理執行入口程序","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們再來看看中斷處理執行入口程序。默認的函數HalHwiDefaultHandler()如下,調用函數HalIntNumGet()獲取中斷號,打印輸出,然後進行死循環。其中函數HalIntNumGet()讀取寄存器ipsr來獲取觸發的中斷的中斷號。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"LITE_OS_SEC_TEXT_MINOR VOID HalHwiDefaultHandler(VOID)\n{\n UINT32 irqNum = HalIntNumGet();\n PRINT_ERR(\"%s irqNum:%d\\n\", __FUNCTION__, irqNum);\n while (1) {}\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​繼續來看中斷處理執行入口程序HalInterrupt(),源碼如下。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⑴處把全局變量g_intCount表示的正在處理的中斷數量加1,在中斷執行完畢後,在⑹處再把正在處理的中斷數量減1。⑵處調用函數HalIntNumGet()獲取中斷號,⑶、⑸處調用的函數HalPreInterruptHandler(),HalAftInterruptHandler()在執行中斷處理程序前、後可以處理些其他操作,當前默認爲空函數。⑷處根據中斷號從中斷處理程序數組中獲取中斷處理程序,不爲空就調用執行。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"LITE_OS_SEC_TEXT VOID HalInterrupt(VOID)\n{\n UINT32 hwiIndex;\n UINT32 intSave;\n\n#if (LOSCFG_KERNEL_RUNSTOP == 1)\n SCB->SCR &= (UINT32) ~((UINT32)SCB_SCR_SLEEPDEEP_Msk);\n#endif\n\n intSave = LOS_IntLock();\n\n⑴ g_intCount++;\n\n LOS_IntRestore(intSave);\n\n⑵ hwiIndex = HalIntNumGet();\n\n OsHookCall(LOS_HOOK_TYPE_ISR_ENTER, hwiIndex);\n\n⑶ HalPreInterruptHandler(hwiIndex);\n\n#if (OS_HWI_WITH_ARG == 1)\n if (g_hwiHandlerForm[hwiIndex].pfnHandler != 0) {\n g_hwiHandlerForm[hwiIndex].pfnHandler((VOID *)g_hwiHandlerForm[hwiIndex].pParm);\n }\n#else\n if (g_hwiHandlerForm[hwiIndex] != 0) {\n⑷ g_hwiHandlerForm[hwiIndex]();\n }\n#endif\n\n⑸ HalAftInterruptHandler(hwiIndex);\n\n OsHookCall(LOS_HOOK_TYPE_ISR_EXIT, hwiIndex);\n\n intSave = LOS_IntLock();\n⑹ g_intCount--;\n LOS_IntRestore(intSave);\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3、開關中斷","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,分享下開、關中斷的相關知識,開、關中斷分別指的是:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開中斷","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"執行完畢特定的短暫的程序,打開中斷,可以響應中斷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關中斷","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了保護執行的程序不被打斷,關閉相應外部的中斷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對應的開、關中斷的函數定義在文件kernel\\arch\\include\\los_context.h中,代碼如下。⑴處的UINT32 LOS_IntLock(VOID)會關閉中斷,暫停響應中斷。⑵處的函數VOID LOS_IntRestore(UINT32 intSave)可以用來恢復UINT32LOS_IntLock(VOID)函數關閉的中斷,UINT32 LOS_IntLock(VOID)的返回值作爲VOIDLOS_IntRestore(UINT32 intSave)的參數進行恢復中斷。⑶處的函數UINT32 LOS_IntUnLock(VOID)會使能中斷,可以響應中斷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" UINTPTR HalIntLock(VOID);\n⑴ #define LOS_IntLock HalIntLock\n\n VOID HalIntRestore(UINTPTR intSave);\n⑵ #define LOS_IntRestore HalIntRestore\n\n UINTPTR HalIntUnLock(VOID);\n⑶ #define LOS_IntUnLock HalIntUnLock","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"​可以看出,LOS_IntLock、LOS_IntRestore和LOS_IntUnLock是定義的宏,他們對應定義在文件","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"kernel\\arch\\arm\\cortex-m7\\gcc\\los_dispatch.S中的彙編函數,源碼如下。我們分析下這些彙編函數。寄存器PRIMASK是單一bit位的寄存器,置爲1後,就關掉所有可屏蔽異常,只剩下NMI和硬故障HardFault異常可以響應。默認值是0,表示沒有關閉中斷。彙編指令CPSID I會設置PRIMASK=1,關閉中斷,指令CPSIEI設置PRIMASK=0,開啓中斷。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"⑴處HalIntLock函數把寄存器PRIMASK數值寫入寄存器R0返回,並執行CPSIDI關閉中斷。⑵處HalIntUnLock函數把寄存器PRIMASK數值寫入寄存器R0返回,並執行指令CPSIEI開啓中斷。兩個函數的返回結果可以傳遞給⑶處HalIntRestore函數,把寄存器狀態數值寫入寄存器PRIMASK,用於恢復之前的中斷狀態。不管是HalIntLock還是HalIntUnLock,都可以和ArchIntRestore配對使用。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":" .type HalIntLock, %function\n .global HalIntLock\nHalIntLock:\n .fnstart\n .cantunwind\n\n⑴ MRS R0, PRIMASK\n CPSID I\n BX LR\n .fnend\n\n .type HalIntUnLock, %function\n .global HalIntUnLock\nHalIntUnLock:\n .fnstart\n .cantunwind\n\n⑵ MRS R0, PRIMASK\n CPSIE I\n BX LR\n .fnend\n\n .type HalIntRestore, %function\n .global HalIntRestore\nHalIntRestore:\n .fnstart\n .cantunwind\n\n⑶ MSR PRIMASK, R0\n BX LR\n .fnend","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"小結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文帶領大家一起剖析了鴻蒙輕內核的中斷模塊的源代碼,掌握中斷相關的概念,中斷初始化操作,中斷創建、刪除,開關中斷操作等。後續也會陸續推出更多的分享文章,敬請期待,也歡迎大家分享學習、使用鴻蒙輕內核的心得,有任何問題、建議,都可以留言給我們: ","attrs":{}},{"type":"link","attrs":{"href":"https://gitee.com/openharmony/kernel_liteos_m/issues","title":"","type":null},"content":[{"type":"text","text":"https://gitee.com/openharmony/kernel_liteos_m/issues","attrs":{}}]},{"type":"text","text":" 。爲了更容易找到鴻蒙輕內核代碼倉,建議訪問 ","attrs":{}},{"type":"link","attrs":{"href":"https://gitee.com/openharmony/kernel_liteos_m","title":"","type":null},"content":[{"type":"text","text":"https://gitee.com/openharmony/kernel_liteos_m","attrs":{}}]},{"type":"text","text":" ,關注Watch、點贊Star、並Fork到自己賬戶下,謝謝。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://bbs.huaweicloud.com/blogs?utm_source=infoq&utm_medium=bbs-ex&utm_campaign=iot&utm_content=content","title":"","type":null},"content":[{"type":"text","text":"點擊關注,第一時間瞭解華爲雲新鮮技術~","attrs":{}}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章