鸿蒙轻内核M核源码分析系列十七(3) 异常信息ExcInfo 原创 精华
鸿蒙轻内核M核源码分析系列十七(3) 异常信息ExcInfo
【本文正在参与优质创作者激励】
ExcHook异常钩子模块是OpenHarmony LiteOS-M
内核的一个可选组件,提供注册钩子函数LOS_RegExcHook
、解除注册钩子函数LOS_UnRegExcHook
等操作接口。发生系统时,支持保存异常上下文、任务信息、队列信息、中断寄存器状态、任务切换信息、内存分配等信息。由于异常钩子模块内容较多,我们分为几篇进行分析源码,分别介绍异常钩子函数的类型,如何注册和解除注册钩子函数,如何转储异常信息等。本篇介绍下异常钩子模块发生系统中断异常时如何转储异常信息。
本文中所涉及的源码,以OpenHarmony LiteOS-M
内核为例,均可以在开源站点https://gitee.com/openharmony/kernel_liteos_m 获取。鸿蒙轻内核异常钩子模块代码主要在components\exchook
目录下。
1、异常信息的宏定义、枚举和结构体
在文件components\exchook\los_exc_info.h
定义了异常信息的相关宏定义、枚举和结构体。如下所示的宏定义为各种异常信息的大小,可以参考下面的异常信息存储区域分布图进行直观的理解,前4字节保存异常信息存储区域的大小,然后分别是异常上下文、任务、队列,中断寄存器,任务切换,内存分配情况的数据信息,最后4字节保存的是异常类型的最大值。
异常上下文存储区域的详细分布如下图所示,保存异常信息类型和信息大小,然后分别存储ExcInfo和上下文信息。其他异常信息类似,不再提供。
从文件中定义的枚举,支持的异常信息类型包含上下文、任务、对外、中断寄存器、任务切换和内存分配信息。枚举定义如下:
2、异常信息初始化
在文件kernel\src\los_init.c
中的函数UINT32 LOS_KernelInit(VOID)
内会调用OsExcMsgDumpInit()
函数进行初始化,代码片段如下。该初始化代码被宏LOSCFG_PLATFORM_EXC
包围,需要开启该宏才能生效。
在分析函数OsExcMsgDumpInit
代码之前,我们先看下函数OsExcRegister
的代码。函数比较简单,⑴处的g_excArray[]
异常信息转储函数数组,支持发生异常时调用这些函数存储任务、内存、中断寄存器等信息,⑵处标记异常信息转储函数是否有效,每个类型的异常信息转储函数只能设置一次。
函数OsExcMsgDumpInit
代码定义在components\exchook\los_exc_info.c
,代码如下所示。⑴处的OS_SYS_MEM_NUM
来自kernel\include\los_config.h
配置文件,在记录内存信息时,会记录每个内存块内存节点的信息,该配置数值表示可以记录的内存块内存节点的数量。
⑵处的g_excMsgArray
是个字节数组用于存储异常信息,g_excContent
是执行字节数组的指针,存储异常信息时该指针不断指向字节数组的后面的位置。⑶处开始的代码调用OsExcRegister()
函数分别设置上下文、任务、队列、中断、任务切换、内存等异常信息转储函数。具体的异常信息转储函数在后文分析。⑷处代码为中断异常类型注册异常钩子函数OsExcMsgDump()
。
3、中断异常钩子函数OsExcMsgDump
函数OsExcMsgDump()
是注册的对应中断异常类型的异常钩子函数。当发生中断异常时,会执行该函数转储异常信息到g_excMsgArray
数组,转储前执行⑴把该内存区域初始化为0xFF。⑵处把转储区的前4个字节存储异常信息的大小,然后g_excContent
指针往后移动4个字节。然后遍历g_excArray[]
异常信息转储函数数组循环执行,会依次都各类信息转储到g_excMsgArray
数组。转储信息后执行⑷把指定区域设置异常信息类型的最大值,然后g_excContent
指针往后移动4个字节。
4、支持的异常信息转储函数
从枚举类型ExcInfoType
,可以得知支持转储的异常信息有6类,对应的转储函数在VOID OsExcMsgDumpInit(VOID)
函数中进行注册。我们挑2个简单看下这些转储函数是如何工作。
4.1 OsExcContentGet上下文转储
上下文转储是第一块要转储的信息,保存异常上下文信息。⑴处获取存储区域的结束地址。⑵处存储异常信息类型,然后g_excContent
指针往后移动4个字节。⑶处存储信息大小,然后g_excContent
指针往后移动4个字节。⑷处把g_excInfo
异常信息复制到存储区域当前指向的位置,其中excContentEnd - (UINTPTR)g_excContent
用于保证复制不会越界溢出,然后继续后移指针。⑸处转储上下文信息,然后继续后移指针,完成上下文信息转储。
4.2 OsExcSaveIntStatus中断寄存器信息转储
OsExcSaveIntStatus()
函数用于转储中断寄存器的数据,⑴、⑵和⑶和其他转储函数类似,分别是获取存储区域的结束地址,设置类型和大小信息,并后移g_excContent
指针。⑷处的OS_NVIC_SETENA_BASE
定义在kernel\arch\arm\cortex-m7\gcc\los_arch_interrupt.h
,是Interrupt enable register
中断使能寄存器的地址,它的大小由OS_NVIC_INT_ENABLE_SIZE
定义。后续的代码分别转储其他中断寄存器,比如Interrupt Set-Pending Registers
中断设置请求寄存器的地址OS_NVIC_SETPEND_BASE
、Interrupt Active Bit Register
中断活跃寄存器的地址OS_NVIC_INT_ACT_BASE
、Interrupt Priority Register
中断优先级寄存器的地址OS_NVIC_PRI_BASE
,这些中断寄存器可以查看官网了解更多,或者查看下图。
⑸处的代码是System Handler Priority Register
系统处理优先级寄存器的地址OS_NVIC_EXCPRI_BASE
,⑹处是System Handler Control and State Register
系统处理控制和状态寄存器的地址OS_NVIC_SHCSR
、⑺处是Interrupt Control and State Register
中断控制和状态寄存器的地址OS_NVIC_INT_CTRL
,有关这些寄存器的信息可以访问官网https://developer.arm.com/documentation/ddi0489/f/system-control/register-summary。
小结
本文介绍了异常信息的转储区域分布情况,介绍异常信息如何初始化,并介绍了两个主要的异常信息转储函数。感谢阅读,如有任何问题、建议,都可以博客下留言给我,谢谢。
【本文正在参与优质创作者激励】
为大佬点赞。
秋浓桂花香。。。