1. 说明 #
本文记录我在移植 SMP 过程中遇到的一些问题和解决思路。
2. 问题记录 #
2.1 lib 模式测例运行时会进入 Exception handler #
分析后发现是 非法指令 的问题,造成非法指令的原因,是因为该指令的内存地址被篡改了。这种问题在 reL4 中挺常见的,因为毕竟用 rust 移植 C 中大量的指针操作,难免会遇到问题。比如 zhuyi 发现的问题
回到本问题,根因是因为 SmpStateData 中少了两个字段,导致和 seL4 中的数据结构大小不同,给这个结构体实例赋值的时候造成了内存越界,修改了内存。
在遇到类似问题时(测例运行一半卡住),查问题的思路是
- 在 c_handle_exception 处打个断点,看是否在预期外的阶段抛出异常。如果没有异常,那是其他代码实现的问题,暂且不讨论。
- 发现存在预期外的异常,查看错误原因,找到错误发生的位置。
- 如果是非法指令,我会在快到报错点的时候在该位置打上断点,然后查看该位置在发生异常时是否被改了
- 如果报非法内存,那就查看该位置在什么时候变得不可读取了,如果确实从可读取变成不可读取,那基本是页表类的问题
- 如果是指令被改造成的非法指令,那我们首先怀疑是内存越界。这个时候就要按照情况分析,大部分情况下,都是一连串的改动,最终造成了非法指令。比如内存越界修改了内核栈,破坏了上下文,上下文被破坏后最终指向了一个非法地址。也有可能是内存越界后,直接修改了某个指令地址。后面的情况就需要具体分析了。
2.2 aarch64 下,IPI 中断发送不生效 #
在进行 aarch64 移植时,发现 SMP IPC 测试中,CPU1 中有个任务在阻塞等待接受,当 CPU0 任务发送后,CPU0 无法通知 CPU1 该任务可以继续执行了,导致 CPU1 始终处于 idle 线程中,无法继续测试。
在 debug 中发现了以下问题
- aarch64 中 invalid irq 是 0xffff,而之前设置的是 0
- aarch64 中 irq 分为 local 和 global,smp 下 irq+cpuid 产生一个映射关系,而不能直接使用 irq 作为 active_irq 的 index
- aarch64 中断号是低 10 位有效,获得的 irq 需要加一个 10bit 的 mask,10~12 位是 cpu id。但是之前没有类似的处理,直接使用获取的中断号,在成中断号错误。
总之以上一系列对于中断处理的错误,造成了 arm 中断无法正常获取,也就无法正常通信。
查类似问题的思路就是不断缩小问题可能范围。
- 首先我确定是 IPI 通信的问题
- 通过代码确认发送没有问题,而且发送简单很多,所以暂定没有问题
- 然后就是看中断处理的代码,和 seL4 不断比较,最终发现所有问题
3. 未解问题 #
- aarch64 smp 模式下,reL4 运行时间比 seL4 慢,大概有 30% 的差距,找不到原因。