异常处理 (Panic System)
Proka Kernel 采用了一套健壮的异常处理机制,旨在系统发生不可恢复错误时,提供清晰的诊断信息并保护硬件状态。
核心设计
当内核触发 panic! 或发生未捕获的 CPU 异常(如 Page Fault)时,系统会进入 Panic 流程。
1. 状态锁定与现场捕获
在进入 Panic 处理函数的第一时间,内核会执行以下操作:
- 禁用中断:通过
cli指令防止嵌套中断干扰。 - 寄存器快照:捕获触发 Panic 瞬间的通用寄存器(RAX, RBX, RCX…)和关键控制寄存器(RIP, RFLAGS, RSP, RBP)。
- 异常信息存储:如果是 CPU 中断引起的 Panic,中断处理程序会将异常类型和错误码写入全局的
EXCEPTION_INFO锁中。
2. 栈回溯 (Stack Backtrace)
为了帮助开发者定位错误,内核实现了基于帧指针(Frame Pointer)的调用栈回溯。
- 实现机制:通过在编译选项中强制开启帧指针 (
-C force-frame-pointers=yes),使编译器在每个函数起始处维护RBP链。 - 回溯逻辑:
- 捕获当前
RBP。 - 跳过第一层(Panic 处理器自身)。
- 循环迭代:读取
[RBP + 8]作为返回地址,读取[RBP]作为上一层帧指针。
- 捕获当前
- 安全性:
- 限制最大深度为 16 层。
- 验证地址是否处于内核高半区内存空间。
- 检查地址对齐及链的增长方向,防止死循环。
输出界面
Proka Kernel 提供双重 Panic 信息输出:
图形化蓝屏 (BSoD)
如果帧缓冲(Framebuffer)可用,内核会切换到专用的 Panic 控制台(功能简陋),并在屏幕上绘制:
- 错误原因:Panic 宏提供的字符串消息。
- 源代码位置:触发错误的文件名 and 行号。(依赖于Rust的core,可能不是真正的源码位置)
- 系统状态:开机时长、关键寄存器状态。
- 通用寄存器:十六进制显示的寄存器列表。
- 调用栈:回溯得到的地址列表。
串口输出
所有 Panic 信息也会同步发送到串口 (Serial Port),方便通过开发机日志捕捉。
调试建议
当看到栈回溯地址时,可以使用 addr2line 工具配合内核 ELF 文件进行解析:
# 将 0xffffffff80001234 替换为实际的回溯地址
addr2line -e output/kernel 0xffffffff80001234
测试模式下的 Panic
在单元测试模式下,Panic 处理器会重定向到测试框架。它会打印错误信息并执行 long_jmp 跳回测试调度器,从而允许测试套件继续运行后续测试项,而不是直接挂起整个系统。