1.概述¶
稳定性对项目交付、用户体验有着非常重要的影响,一般定义的稳定性问题是遇到了系统异常重启或者系统卡死等,即无法按照预期为客户继续提供功能和服务。地平线SoC平台提供了多种调试手段,去分析系统遇到的稳定性问题。
首先我们需要了解征程系列的软硬件方案及异常reset路径,通过了解异常路径定位发生异常的节点和步骤,定位到问题方向。
其次,我们需要对发生问题节点提取的调试信息,包括抓取log、抓取ramdump等,对于复杂问题,可能需要不断的迭代patch以获取更多调试信息,以缩小问题的范围。
对于复杂问题,可能需要使用特定的工具去分析问题,如crash-utility,T32,ftrace等。
所以我们将稳定性问题的概述指导分为下面几个章节进行介绍。
2. 常见问题¶
2.1.kernel panic¶
kernel panic是最常见的系统异常,在reset_reason.txt中显示为kpanic。
一般通过pstore log就能看到panic时的栈和寄存器信息,通过分析上下文配合符号表及gdb等工具经常能够直接定位问题。
对于复杂问题,需要开启ramdump,抓取dump后进行分析。
一个典型的kpanic如下:
2.2. Memory corruption¶
Memory corruption类问题一般表现也是kpanic,但是最明显的标志是问题的随机性和不可解释性,出现这类情况,一般要考虑是内存使用上出现了UAF(Use-After-Free),OOB(Out-of-Bounds)。
这类问题的难点在于,系统出现异常crash时,已经是前面时间发生踩踏的结果,所以需要定位到踩踏发生的位置,才能正向解决这类问题,一般在系统中存在下述两类踩踏问题:
a> Linux内核发生踩踏:
对于Acore中运行的Linux系统,KASAN是目前检查内存访问越界(Out-Of-Bound)和释放后访问(Use-After-Free)问题最有效的工具,KASAN依赖编译器支持,当前GCC-12.2可以支持全功能的KASAN,但是KASAN对性能和内存损耗非常严重,对于slub内存的使用问题,轻量级的LUB_DEBUG往往也能提供帮助,但功能比较受限且提供的信息也比较有限。
b> SoC子系统间的内存踩踏:
在J6X SoC拥有Acore、BPU、VDSP、Secure World(EL3)的多子系统SoC, DDR内存空间根据需求划分给不同子系统,如果子系统间内存出现踩踏,整机系统可能会出现各种随机异常。
J6X SoC中使用firewall对SoC各子系统间的内存越界踩踏进行检测,当发生踩踏时由EL3触发crash。
2.3. Watchdog¶
J6X SoC中有2路watchdog,目前使用wdt0(监控linux irq),wdt1(监控linux优先级为50的rt kthread)。从/log/reset_reason.txt中可以看到wdt的reason:
wdt导致重启后,系统会保存pstore log,通过检查pstore获取异常信息。
wdt狗咬中断/事件由MCU域处理,MCU域进行重启。
wdt0:一般是kernel中某个CPU处于长时间无法响应中断的状态,J6X平台上在wdt1狗咬时间(IRQ_WDT_TIMEOUT)到后会触发一个gic中断,在这个中断中会使用NMI将所有cpu的调用栈打印。
wdt1:一般是kernel中某个CPU处于长时间无法调度优先级为50的rt kthread的状态,J6X平台上在wdt2狗咬时间(IRQ_WDT_TIMEOUT)到后会触发一个gic中断,在这个中断中会使用NMI将所有cpu的调用栈打印。
2.4 firewall
在J6X SoC拥有Acore、BPU、GPU、VDSP0、Secure World(EL3)等多个子系统,DDR内存空间根据需求划分给不同子系统。
如果子系统间内存/寄存器空间出现踩踏,整机系统可能会出现各种随机异常。firewall是J6X SoC上的硬件单元,功能就是根据配置捕获子系统间的内存越界踩踏,当发生踩踏时由EL3触发crash。
在MCU域的log中会输出发生越界访问的地址信息和master信息,输出示例如下:ID为0xd0的master尝试读地址为0x80000000的内存空间。
MCU域主动触发firewall违例:
MCU域的违例信息log:
J6X 部分内存的firewall权限设置:
地址区间 | 读权限 | 写权限 | 安全属性 |
|---|---|---|---|
0x80000000 ~ 0xaa00_0000 | MCU不可读 | MCU不可读 | non-secure |
0xaa100000 ~ 0xb3ff_ffff | MCU不可读 | MCU不可读 | non-secure |
0xb6000000 ~ 0xceff_ffff | MCU不可读 | MCU不可读 | non-secure |
0xcf500000 ~ 0xffff_ffff | MCU不可读 | MCU不可读 | non-secure |
0xa2000000 ~ 0xa5dfffff | non-secure不可读 | non-secure不可写 | secure |
0xa9e00000 ~ 0xa9fff000 | non-secure不可读 | non-secure不可写 | secure |
0xa0100000 ~ 0xa026f000 | non-secure不可读 | non-secure不可写 | secure |
0xa0270000 ~ 0xa027f000 | non-secure可读 | non-secure不可写 | secure |
Master ID定义,详见:hbbin_j6p/boot/j6p/bl31-dts/include/hobot_firewall.h。