中断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":{}}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章