• 使用SDEI上报RAS故障


    Software Delegated Exception Interface (SDEI) 软件委托异常接口的一种典型应用场景是利用APEI( ACPI Platform Error Interface)用作固件优先(firmware first)的RAS故障处理的通知机制。事实上SDEI只是在ACPI6.2版本引入的一种新的通知机制(firmware to OS),可以不受中断屏蔽的影响。
    在这里插入图片描述

    Firmware First Error Handling with SDEI

    RAS是系统鲁棒性的重要特性,重点关注由硬件产生的故障,这些故障一般有两种处理方式:firmware first 和 kernel first。其中firmware first的处理流程如下图:

    在这里插入图片描述

    1. RAS节点检测到故障
    2. Firmware收到故障事件(中断)
    3. 故障事件转发到MM驱动
    4. MM驱动从故障记录寄存器中读取RAS故障并生成CPER(Common Platform Error Record)故障记录,返回EL3
    5. EL3通过SDEI通知OS
    6. OS读CPER并处理故障

    从上面的流程可以看出,SDEI是firmware到OS的通知机制,而CPER是firmware到OS传递故障信息的载体。
    SDEI和CPER都是通过APEI中一种叫做HEST(Hardware Error Source Table)的表来承载, HEST表支持多种故障源类型,其中RAS故障通过GHES(Generic Hardware Error Source) V2结构来表示。

    在这里插入图片描述

    1. 其中GHES的Notification Structure用来通知OS,SDEI作为类型11的通知方式,并把32位事件号存储在vector字段
    2. 故障信息记录在GHES的Error Status Address,这是一个GAS(Generic Address Structure)结构体,这个结构体的Address指向记录错误数据的block( Generic Error Status Block),每个block包含一个或多个Generic Error Data Entry,CPER就是Error Data Entry的一个字段。
    3. firmware在初始化阶段检测故障源,创建GHES并填入到HEST表中发布给OS
    4. OS解析HEST( Hardware ErrorSource Table’s) 的 GHES( Generic Hardware Error Source) entry的时候,使用SDEI调用为每个event注册一个处理函数handler
    5. RAS故障发生时通过中断通知Firmware
    6. firmware从RAS扩展寄存器中读取RAS故障并记录CPER,然后通过SMC调用该故障对应的event注册的处理函数(故障与event的映射关系需要预先定义)
    7. OS执行该处理函数,从映射的内存地址中读取CPER, 进一步处理故障

    在这里插入图片描述

    SDEI初始化过程

    linux中的SDEI驱动初始化代码在 ./drivers/firmware/arm_sdei.c 的sdei_probe,
    SDEI初始化过程主要做3件事:

    1. 初始化sdei_firmware_call,明确SDEI调用是HVC还是SMC,可以通过acpi或者DTS表选择
    2. 通过SDEI_VERSION调用与firmware对齐版本号
    3. 初始化sdei_entry_point,也就是从firmware跳到OS的asm入口地址__sdei_asm_handler

    OS通过sdei_firmware_call调用到了firmware会执行sdei_smc_handler,sdei_smc_handler根据function ID执行相应的处理函数,比如SDEI_VERSION调用的function ID为 0xC400_0020,对应的处理函数为sdei_version。

    SDEI注册过程源码分析

    1. ghes_probe根据GHES的Notification Structure的通知类型ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED(11)选择执行apei_sdei_register_ghes. apei_sdei_register_ghes调用sdei_register_ghes完成sdei的注册
    2. sdei_register_ghes中首先从GHES的Notification Structure的的vector字段获取到event number,调用sdei_event_register为该event注册callback函数ghes_sdei_normal_callback或ghes_sdei_critical_callback,然后通过sdei_event_enable使能该event
    3. sdei_event_register中首先通过sdei_event_create()把event添加到sdei_list,然后通过sdei_api_event_register()-> invoke_sdei_fn( SDEI_EVENT_REGISTER
      ) -> sdei_firmware_call(SDEI_EVENT_REGISTER) 注册入口地址 sdei_entry_point
    4. sdei_firmware_call通过HVC或SMC跳到firmware执行sdei_smc_handler,然后根据function ID找到对应的处理函数sdei_event_register完成事件注册

    SDEI事件分配过程源码分析

    1. RAS故障(eg: External Abort)产生时EL3会收到相应的中断,进而调用RAS驱动处理故障,接着会调用sdei_dispatch_event(event_num)把故障分发到sdei client去处理
    2. sdei_dispatch_event通过event_num找到注册好的入口地址sdei_entry_point,然后保存Non-secure上下文并通过setup_ns_dispatch填充要跳转的SDEI client的上下文,最后调用begin_sdei_synchronous_dispatch设置跳转点dispatch_jmp(从client返回的点),退出EL3
    3. setup_ns_dispatch中会设置event handler的参数,并通过sdei_set_elr_spsr设置ELR为注册事件的入口地址sdei_entry_point, 设置SPSR屏蔽中断(DISABLE_ALL_EXCEPTIONS)
    4. 退出EL3后就跳到事件的入口地址sdei_entry_point,也就是前面初始化的汇编函数__sdei_asm_handler
    5. __sdei_asm_handler调用__sdei_handler->do_sdei_event->sdei_event_handler, sdei_event_handler从参数中获取到event_num, 然后执行为该event注册的callback函数ghes_sdei_normal_callback或ghes_sdei_critical_callback
    6. 这两个callback函数都会调用__ghes_sdei_callback,这里会从GHES的里获取到Generic Error Status Block添加到ghes_estatus_llist中,清除Block故障状态并通过read_ack_register给firmware一个应答,然后添加一个irq work也就是ghes_proc_in_irq到中断队列中
    7. ghes_proc_in_irq遍历ghes_estatus_llist并调用ghes_do_proc执行具体的故障处理动作
    8. 故障处理完之后会回到__sdei_asm_handler中调用sdei_handler_exit,通过SMC或HVC跳到firmware执行sdei_smc_handler->sdei_event_complete
    9. sdei_event_complete中恢复上下文,调用end_sdei_synchronous_dispatch跳到dispatch_jmp继续执行。

    参考

    ACPI Specification

    Reliability, Availability, and Serviceability(RAS) on ARM64

    Firmware First Error Handling on ARM Neoverse Reference Design Platforms

  • 相关阅读:
    【Shell】进程内存过高告警脚本
    JavaScript中 Generator 函数详解
    央媒发稿不能改?媒体发布新闻稿有哪些注意点
    分词phrase
    React16、18 使用 Redux
    【遗传算法】Python Geatpy工具箱介绍
    网络专线学习
    QT6不支持QDesktopWidget包含头文件报错Qt 获取设备屏幕大小
    go语言基础之变量
    LocalStroage,SessionStroage,Cookide,IndexedDB
  • 原文地址:https://blog.csdn.net/jingr1/article/details/126216896