Linux内核do_sea()分析
1、do_sea()函数用途
该函数是硬件同步错误的处理函数,分下面4种情况。
“synchronous external abort”:SEA的内核处理入口。
“level x (translation table walk)”:未知
“synchronous parity or ECC error”:待支持的RAS错误处理
“level x synchronous parity error (translation table walk)”:待支持的RAS错误处理
2、do_sea()流程
函数代码如下:
641 static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
642 {
643 const struct fault_info *inf;
644 void __user *siaddr;
645
646 inf = esr_to_fault_info(esr);
647
648 /*
649 * Return value ignored as we rely on signal merging.
650 * Future patches will make this more robust.
651 */
652 apei_claim_sea(regs);
653
654 if (esr & ESR_ELx_FnV)
655 siaddr = NULL;
656 else
657 siaddr = (void __user *)addr;
658 arm64_notify_die(inf->name, regs, inf->sig, inf->code, siaddr, esr);
659
660 return 0;
661 }
其中apei_claim_sea()用来解析APEI的表格,获取固件传递的数据。
arm64_notify_die()是处理的关键函数,处理区分用户态和内核态,用户态直接杀进程,内核态则调用die()。die()其实就是oops的执行程序。oops正常只是打印一些调用栈信息,如果内核还能继续运行,还是可以接着往下跑的,但如果配置了panic_on_oops=1,就会panic。
顺便说下,SEA的设计预期是,如果内核态触发SEA,就要panic,而不是让核接着运行。
3、panic流程
然后系统panic了,CPU的状态是怎样的呢?
从代码来看,该处理函数会先关本地中断,然后执行smp_send_stop()或者crash_smp_send_stop()来停止其它核。如果配置了定时重启,就会执行emergency_restart()做紧急重启,否则,会再打开本地中断,防止丢失一些重要信息的打印。
参考内核代码kernel/panic.c
4、smp_send_stop()
该函数在arch/arm64/kernel/smp.c中实现的, 主要做的事情就是调用smp_cross_call(&mask, IPI_CPU_STOP)让其它核停止。
smp_cross_call的执行涉及了IPI机制,可以如下博文:
一个bug引发的linux smp 血案
其实就是发送一个消息给另外的核,然后让其处理,处理函数是handle_IPI()。
IPI_CPU_STOP事件的处理方式,是把核标记成offline状态,然后MASK住DAIF,让核在那里空跑,如下函数所示:
833 static void local_cpu_stop(void)834 {835 set_cpu_online(smp_processor_id(), false);836837 local_daif_mask();838 sdei_mask_local_cpu();839 cpu_park_loop();840 }
其中local_daif_mask()实现如下:
21 /* mask/save/unmask/restore all exceptions, including interrupts. */22 static inline void local_daif_mask(void)23 {24 WARN_ON(system_has_prio_mask_debugging() &&25 (read_sysreg_s(SYS_ICC_PMR_EL1) == (GIC_PRIO_IRQOFF |26 GIC_PRIO_PSR_I_SET)));2728 asm volatile(29 "msr daifset, #0xf // local_daif_mask\n"30 :31 :32 : "memory");3334 /* Don't really care for a dsb here, we don't intend to enable IRQs */35 if (system_uses_irq_prio_masking())36 gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);3738 trace_hardirqs_off();39 }
备注:mask住daif之后,EL3的中断还是能进的。
5、备注
5.1、内核DAIF能否屏蔽EL3的中断
答案是不能,解释可参考ARM的规范。

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
