鸿蒙轻内核M核源码分析系列十七(3) 异常信息ExcInfo

news2024/11/16 1:35:23

本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例,均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_m 获取。鸿蒙轻内核异常钩子模块代码主要在components\exchook目录下。


1、异常信息的宏定义、枚举和结构体

在文件components\exchook\los_exc_info.h定义了异常信息的相关宏定义、枚举和结构体。如下所示的宏定义为各种异常信息的大小,可以参考下面的异常信息存储区域分布图进行直观的理解,前4字节保存异常信息存储区域的大小,然后分别是异常上下文、任务、队列,中断寄存器,任务切换,内存分配情况的数据信息,最后4字节保存的是异常类型的最大值。

异常上下文存储区域的详细分布如下图所示,保存异常信息类型和信息大小,然后分别存储ExcInfo和上下文信息。其他异常信息类似,不再提供。

#define INFO_TYPE_AND_SIZE      8

#define MAX_SCENE_INFO_SIZE     (INFO_TYPE_AND_SIZE + sizeof(ExcInfo) + sizeof(EXC_CONTEXT_S))
#define MAX_TSK_INFO_SIZE       (INFO_TYPE_AND_SIZE + sizeof(TSK_INFO_S) * (LOSCFG_BASE_CORE_TSK_LIMIT + 1))

#if (LOSCFG_BASE_IPC_QUEUE == 1)
#define MAX_QUEUE_INFO_SIZE     (INFO_TYPE_AND_SIZE + sizeof(QUEUE_INFO_S) * LOSCFG_BASE_IPC_QUEUE_LIMIT)
#else
#define MAX_QUEUE_INFO_SIZE     (0)
#endif

#if (LOSCFG_BASE_CORE_EXC_TSK_SWITCH == 1)
#define MAX_SWITCH_INFO_SIZE    (INFO_TYPE_AND_SIZE + (sizeof(UINT32) + sizeof(CHAR) * LOS_TASK_NAMELEN) * OS_TASK_SWITCH_INFO_COUNT)
#else
#define MAX_SWITCH_INFO_SIZE    (0)
#endif

#define MAX_MEM_INFO_SIZE       (INFO_TYPE_AND_SIZE + sizeof(MemInfoCB) * OS_SYS_MEM_NUM)
#define MAX_EXC_MEM_SIZE        (INFO_TYPE_AND_SIZE + MAX_SCENE_INFO_SIZE + MAX_TSK_INFO_SIZE + MAX_QUEUE_INFO_SIZE + MAX_INT_INFO_SIZE + MAX_SWITCH_INFO_SIZE + MAX_MEM_INFO_SIZE)

从文件中定义的枚举,支持的异常信息类型包含上下文、任务、对外、中断寄存器、任务切换和内存分配信息。枚举定义如下:

typedef enum {
    OS_EXC_TYPE_CONTEXT     = 0,
    OS_EXC_TYPE_TSK         = 1,
    OS_EXC_TYPE_QUE         = 2,
    OS_EXC_TYPE_NVIC        = 3,
    OS_EXC_TYPE_TSK_SWITCH  = 4,
    OS_EXC_TYPE_MEM         = 5,
    OS_EXC_TYPE_MAX         = 6
} ExcInfoType;

2、异常信息初始化

在文件kernel\src\los_init.c中的函数UINT32 LOS_KernelInit(VOID)内会调用OsExcMsgDumpInit()函数进行初始化,代码片段如下。该初始化代码被宏LOSCFG_PLATFORM_EXC包围,需要开启该宏才能生效。

#if (LOSCFG_PLATFORM_EXC == 1)
    OsExcMsgDumpInit();
#endif

在分析函数OsExcMsgDumpInit代码之前,我们先看下函数OsExcRegister的代码。函数比较简单,⑴处的g_excArray[]异常信息转储函数数组,支持发生异常时调用这些函数存储任务、内存、中断寄存器等信息,⑵处标记异常信息转储函数是否有效,每个类型的异常信息转储函数只能设置一次。

VOID OsExcRegister(ExcInfoType type, EXC_INFO_SAVE_CALLBACK func, VOID *arg)
{
    ExcInfoArray *excInfo = NULL;
    if ((type >= OS_EXC_TYPE_MAX) || (func == NULL)) {
        PRINT_ERR("HalExcRegister ERROR!\n");
        return;
    }
⑴  excInfo = &(g_excArray[type]);
    if (excInfo->valid == TRUE) {
        return;
    }

    excInfo->type = type;
    excInfo->fnExcInfoCb = func;
    excInfo->arg = arg;
⑵  excInfo->valid = TRUE;
}

函数OsExcMsgDumpInit代码定义在components\exchook\los_exc_info.c,代码如下所示。⑴处的OS_SYS_MEM_NUM来自kernel\include\los_config.h配置文件,在记录内存信息时,会记录每个内存块内存节点的信息,该配置数值表示可以记录的内存块内存节点的数量。

⑵处的g_excMsgArray是个字节数组用于存储异常信息,g_excContent是执行字节数组的指针,存储异常信息时该指针不断指向字节数组的后面的位置。⑶处开始的代码调用OsExcRegister()函数分别设置上下文、任务、队列、中断、任务切换、内存等异常信息转储函数。具体的异常信息转储函数在后文分析。⑷处代码为中断异常类型注册异常钩子函数OsExcMsgDump()

VOID OsExcMsgDumpInit(VOID)
{
    g_excQueueMaxNum = LOSCFG_BASE_IPC_QUEUE_LIMIT;
⑴  g_excMemMaxNum = OS_SYS_MEM_NUM;
⑵  g_excContent = (VOID *)g_excMsgArray;

⑶  OsExcRegister(OS_EXC_TYPE_CONTEXT, OsExcContentGet, NULL);
    OsExcRegister(OS_EXC_TYPE_TSK, OsExcTaskMsgGet, &g_taskMaxNum);
#if (LOSCFG_BASE_IPC_QUEUE == 1)
    OsExcRegister(OS_EXC_TYPE_QUE, OsExcQueueMsgGet, &g_excQueueMaxNum);
#endif
    OsExcRegister(OS_EXC_TYPE_NVIC, OsExcSaveIntStatus, NULL);
#if (LOSCFG_BASE_CORE_EXC_TSK_SWITCH == 1)
    OsExcRegister(OS_EXC_TYPE_TSK_SWITCH, OsExcTskSwitchMsgGet, &g_taskSwitchInfo);
#endif
    OsExcRegister(OS_EXC_TYPE_MEM, OsExcMemMsgGet, &g_excMemMaxNum);

⑷  (VOID)LOS_RegExcHook(EXC_INTERRUPT, (ExcHookFn)OsExcMsgDump);
}

3、中断异常钩子函数OsExcMsgDump

函数OsExcMsgDump()是注册的对应中断异常类型的异常钩子函数。当发生中断异常时,会执行该函数转储异常信息到g_excMsgArray数组,转储前执行⑴把该内存区域初始化为0xFF。⑵处把转储区的前4个字节存储异常信息的大小,然后g_excContent指针往后移动4个字节。然后遍历g_excArray[]异常信息转储函数数组循环执行,会依次都各类信息转储到g_excMsgArray数组。转储信息后执行⑷把指定区域设置异常信息类型的最大值,然后g_excContent指针往后移动4个字节。

STATIC VOID OsExcMsgDump(VOID)
{
    UINT32 index;

    /* Ignore the return code when matching CSEC rule 6.6(4). */
⑴  (VOID)memset_s(g_excMsgArray, g_excArraySize, EXC_MSG_ARRAY_INIT_VALUE, g_excArraySize);

⑵  *((UINT32 *)g_excContent) = MAX_EXC_MEM_SIZE;  /* The total length of exception information. */
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);

    for (index = 0; index < OS_EXC_TYPE_MAX; index++) {
        if (!g_excArray[index].valid) {
            continue;
        }
⑶      g_excArray[index].fnExcInfoCb(g_excArray[index].type, g_excArray[index].arg);
    }

⑷  *((UINT32 *)g_excContent) = OS_EXC_TYPE_MAX;
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);
    return;
}

4、支持的异常信息转储函数

从枚举类型ExcInfoType,可以得知支持转储的异常信息有6类,对应的转储函数在VOID OsExcMsgDumpInit(VOID)函数中进行注册。我们挑2个简单看下这些转储函数是如何工作。

4.1 OsExcContentGet上下文转储

上下文转储是第一块要转储的信息,保存异常上下文信息。⑴处获取存储区域的结束地址。⑵处存储异常信息类型,然后g_excContent指针往后移动4个字节。⑶处存储信息大小,然后g_excContent指针往后移动4个字节。⑷处把g_excInfo异常信息复制到存储区域当前指向的位置,其中excContentEnd - (UINTPTR)g_excContent用于保证复制不会越界溢出,然后继续后移指针。⑸处转储上下文信息,然后继续后移指针,完成上下文信息转储。

STATIC UINT32 OsExcContentGet(UINT32 type, VOID *arg)
{
⑴  UINTPTR excContentEnd = MAX_EXC_MEM_SIZE + (UINTPTR)g_excMsgArray;
    errno_t ret;

    (VOID)arg;

    /* save exception info */
⑵  *((UINT32 *)g_excContent) = type;
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);
⑶  *((UINT32 *)g_excContent) = sizeof(ExcInfo) + sizeof(EXC_CONTEXT_S);
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);

⑷  ret = memcpy_s((VOID *)g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (VOID *)&g_excInfo, sizeof(ExcInfo));
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + sizeof(ExcInfo);

⑸  ret = memcpy_s((VOID *)g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   g_excInfo.context, sizeof(EXC_CONTEXT_S));
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + sizeof(EXC_CONTEXT_S);

    return LOS_OK;
}

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_BASEInterrupt Active Bit Register中断活跃寄存器的地址OS_NVIC_INT_ACT_BASEInterrupt 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。

STATIC UINT32 OsExcSaveIntStatus(UINT32 type, VOID *arg)
{
    UINT32 ret;
⑴  UINTPTR excContentEnd = (UINTPTR)MAX_INT_INFO_SIZE + (UINTPTR)g_excContent;

    (VOID)arg;

⑵  *((UINT32 *)g_excContent) = type;
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);

⑶  *((UINT32 *)g_excContent) = EXC_INT_STATUS_LEN;
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);
    /* save IRQ ENABLE reg group */
⑷  ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_SETENA_BASE, OS_NVIC_INT_ENABLE_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_ENABLE_SIZE;

    /* save IRQ PEND reg group */
    ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_SETPEND_BASE, OS_NVIC_INT_PEND_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_PEND_SIZE;

    /* save IRQ ACTIVE reg group */
    ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_INT_ACT_BASE, OS_NVIC_INT_ACT_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_ACT_SIZE;

    /* save IRQ Priority reg group */
    ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_PRI_BASE, OS_NVIC_INT_PRI_SIZE);
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_PRI_SIZE;

    /* save Exception Priority reg group */
⑸  ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_EXCPRI_BASE, OS_NVIC_EXCPRI_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_EXCPRI_SIZE;

    /* save IRQ Handler & SHCSR */
⑹  ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_SHCSR, OS_NVIC_SHCSR_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_SHCSR_SIZE;

    /* save IRQ Control & ICSR */
⑺  ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_INT_CTRL, OS_NVIC_INT_CTRL_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_CTRL_SIZE;

    return LOS_OK;
}


小结

本文介绍了异常信息的转储区域分布情况,介绍异常信息如何初始化,并介绍了两个主要的异常信息转储函数。

如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1800462.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NSSCTF-Web题目7

目录 [SWPUCTF 2022 新生赛]ez_rce 1、题目 2、知识点 3、思路 ​编辑 [MoeCTF 2022]baby_file 1、题目 2、知识点 3、思路 [SWPUCTF 2022 新生赛]ez_rce 1、题目 2、知识点 ThinkPHP V5 框架漏洞的利用&#xff0c;命令执行 由于ThinkPHP5在处理控制器传参时&#xff…

RK3588+FPGA+算能BM1684X:高性能AI边缘计算盒子,应用于视频分析、图像视觉等

搭载RK3588&#xff08;四核 A76四核 A55&#xff09;&#xff0c;CPU主频高达 2.4GHz &#xff0c;提供1MB L2 Cache 和 3MB L3 &#xff0c;Cache提供更强的 CPU运算能力&#xff0c;具备6T AI算力&#xff0c;可扩展至38T算力。 产品规格 系统主控CPURK3588&#xff0c;四核…

38页 | 工商银行大数据平台助力全行数字化转型之路(免费下载)

【1】关注本公众号&#xff0c;转发当前文章到微信朋友圈 【2】私信发送 工商银行大数据平台 【3】获取本方案PDF下载链接&#xff0c;直接下载即可。 如需下载本方案PPT/WORD原格式&#xff0c;请加入微信扫描以下方案驿站知识星球&#xff0c;获取上万份PPT/WORD解决方案&a…

leetcode刷题-栈与队列03

代码随想录栈与队列part02|239. 滑动窗口最大值、347.前 K 个高频元素、总结 239. 滑动窗口最大值347.前 K 个高频元素栈与队列总结 239. 滑动窗口最大值 leetcode题目链接 代码随想录文档讲解 思路&#xff1a; 滑动窗口的移动过程很像一个队列&#xff08;先进先出&#xff0…

『大模型笔记』Transformer系列技术博文汇总!

Transformer系列技术博文汇总&#xff01; 文章目录 第1篇&#xff1a;矩阵乘法概念解释第2篇&#xff1a;使用缩放点积方法的自注意力第3篇&#xff1a;深入探讨多头注意力、自注意力和交叉注意力第4篇&#xff1a;Transformer 架构第5篇&#xff1a;PostLN&#xff0c;PreLN…

Linux存储管理

简介 硬件上的存储设备目前有两类&#xff0c;通过磁头读写信息的机械硬盘和用主控芯片将信息写入晶体管的固态硬盘&#xff0c;硬盘调度算法等知识可以通过前面的操作系统设备管理文章学习&#xff0c;本章只介绍Linux中能对存储设备的操作。 为了让操作系统识别和管理物理磁…

企业差旅费管理如何实现真正的降本增效

看企业发展&#xff0c;不能只看当下&#xff0c;尤其对于看重长期价值的企业家来说&#xff0c;必须要用更长远的目光去看行业的未来。开源节流&#xff0c;扔掉一些没用的包袱减少负担&#xff0c;然后轻装上阵&#xff0c;并寻找企业发展的新增长点&#xff0c;仍然是众多企…

探索未来制造,BFT Robotics引领潮流

“买机器人&#xff0c;上BFT” 在这个快速变化的时代&#xff0c;创新和效率是企业发展的关键。BFT Robotics&#xff0c;作为您值得信赖的合作伙伴&#xff0c;专注于为您提供一站式的机器人采购和自动化解决方案。 产品系列&#xff1a; 协作机器人&#xff1a;安全、灵活、…

Vue3_对接腾讯云COS_大文件分片上传和下载

目录 一、腾讯云后台配置 二、安装SDK 1.script 引入方式 2.webpack 引入方式 三、文件上传 1.new COS 实例 2.上传文件 四、文件下载 腾讯云官方文档&#xff1a; 腾讯云官方文档https://cloud.tencent.com/document/product/436/11459 一、腾讯云后台配置 1.登录 对…

【外汇天眼】选择外汇EA的关键:策略适配、风险控制与稳定性评估

外汇EA&#xff08;Expert Advisor&#xff09;是外汇交易市场中广泛使用的自动化交易系统。它们通过预定义的规则和算法自动执行交易&#xff0c;旨在为交易者提供便捷的交易体验&#xff0c;同时提高交易效率和准确性。本文将从策略选择、风险控制和稳定性评估三个方面&#…

OKP绩效管理系统:助力企业实现卓越绩效

在当今竞争激烈的商业环境中&#xff0c;绩效管理系统成为企业提升效率和竞争力的重要工具。搭贝OKP绩效管理系统通过其强大的功能模块&#xff0c;帮助企业全面优化绩效管理流程&#xff0c;提升员工工作效率和企业整体绩效。本文将详细介绍搭贝OKP绩效管理系统的核心功能模块…

SpringBoot中的WebMvcConfigurationSupport和WebMvcConfigurer

在SpringBoot中可以通过以下两种方式来完成自定义WebMvc的配置&#xff1a; &#xff08;1&#xff09;继承WebMvcConfigurationSupport类 &#xff08;2&#xff09;实现WebMvcConfigurer接口 通过这两种方式完成的WebMvc配置存在差异&#xff0c;本文将对此作简单说明与区…

官网万词霸屏推广 轻松实现百度万词霸屏源码系统 带完整的安装代码包以及搭建教程

系统概述 官网万词霸屏推广源码系统是一款基于先进技术研发的综合性 SEO 工具。它的设计理念是通过智能化的算法和策略&#xff0c;帮助用户快速提升网站在百度等搜索引擎中的排名&#xff0c;实现大量关键词的霸屏效果。该系统整合了多种优化技术&#xff0c;包括关键词研究、…

日本指数实时API接口

日本 指数 实时API接口 # Restful API https://tsanghi.com/api/fin/index/JPN/realtime?token{token}&ticker{ticker}指定指数代码&#xff0c;获取该指数的实时行情&#xff08;开、高、低、收、量&#xff09;。 更新周期&#xff1a;实时。 请求方式&#xff1a;GET。…

Kali linux学习入门

Kali linux学习入门 文章目录 Kali linux学习入门Kali Linux简介Kali Linux工具篇Kali Docker安装Docker 更换国内镜像源Kali 安装 docker compose Kali Linux文档篇Kali Linux 社区篇 Kali Linux简介 Kali Linux是专门用于渗透测试linux操作系统&#xff0c;它由BackTrack发展…

Bev 车道标注方案及复杂车道线解决

文章目录 1. 数据采集方案1.1 传感器方案1.2 数据同步2. 标注方案2.1 标注注意项2.2 4d 标注(时序)2.2.1 4d标签制作2.2.2 时序融合的作用2.2.2.1 时序融合方式2.2.2.2 时序融合难点2.2.2.2 时序实际应用情况3. 复杂车道线解决3.1 split 和merge车道线的解决3.2 大曲率或U形车道…

单列集合.java

单列集合 为了存储不同类型的多个对象&#xff0c;Java提供了一些特殊系列的类&#xff0c;这些类可以存储任意类型的对象&#xff0c;并且存储的长度可变&#xff0c;这些类统称为集合。可以简单的理解为一个长度可变&#xff0c;可以存储不同数据类型的动态数组。集合都位于j…

mysql的binlog占用大量磁盘空间的解决方法

查看当前日志保存天数&#xff1a; mysql> show variables like %expire_logs_days%; ------------------------- | Variable_name | Value | ------------------------- | expire_logs_days | 0 | ------------------------- 1 row in set (0.08 sec) 默认是0&…

Mac - Node/Java 配置安装全流程

Mac - Node/Java 配置安装全流程 一. Git 安装二. Java 相关安装2.1 jenv 版本控制工具2.2 JDK1.8 和 JDK21的安装2.3 maven 安装 三. Node 相关安装3.1 nvm 版本控制工具3.2 Node 版本安装 一. Git 安装 1.我们首先安装一下Homebrew&#xff0c;这个工具很有用&#xff0c;能…

大数据处理学习笔记

sudo tar -zxvf hadoop-1.1.2.tar.gz -C / #解压到/usr/local目录下 sudo mv hadoop-1.1.2 hadoop #重命名为hadoop sudo chown -R python ./hadoop #修改文件权限 //java安装同上给hadoop配置环境变量&#xff0c;将下面代…