DEFINE_IDTENTRY_RAW_ERRORCODE是 Linux 内核 x86 架构中用于定义原始异常入口函数的宏,它封装了硬件异常处理入口的底层汇编粘合逻辑,使开发者能直接编写 C 语言处理函数。
宏的核心作用
这个宏展开后,会定义一个带有struct pt_regs *regs和unsigned long error_code参数的函数,并自动生成对应的汇编入口代码。它的关键特性是“原始”(RAW):调用者不会自动执行idtentry_enter/exit()辅助函数,这意味着中断是禁用的,且需要调用者在函数体内自行处理进入/退出逻辑。
宏定义与展开
#define DEFINE_IDTENTRY_RAW_ERRORCODE(func) \ __visible noinstr void func(struct pt_regs *regs, \ unsigned long error_code)
关键属性说明:
__visible:确保符号对汇编代码可见,因为汇编入口桩需要跳转到这个函数。noinstr:禁止在函数中插入任何插桩代码(如 kprobe、ftrace),因为此时内核环境尚未完全就绪。
与exc_page_fault的关系
exc_page_fault正是通过这个宏定义的:
DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
它在arch/x86/include/asm/idtentry.h中通过DECLARE_IDTENTRY_RAW_ERRORCODE(X86_TRAP_PF, exc_page_fault)声明。当 CPU 触发缺页异常(向量 14)时,硬件会将错误码压栈,然后跳转到汇编入口桩,汇编桩再调用exc_page_fault。
为什么缺页异常需要 “RAW” 模式?
缺页异常的处理路径非常特殊:
需要访问用户内存:处理缺页时可能需要读取用户态指令(如
is_prefetch检测),而标准的idtentry_enter()会改变某些状态,可能干扰这一过程。中断状态敏感:缺页处理中需要精确控制中断的启用/禁用时机,因此不能由宏自动处理。
FRED 兼容性:在支持 FRED(Flexible Return and Event Delivery)的新架构上,
exc_page_fault会被替换为fred_exc_page_fault,但两者最终都调用相同的page_fault_common逻辑。
调用链概览
CPU 触发缺页异常 (向量 14) ↓ 汇编入口桩 (asm_exc_page_fault) ↓ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault) ↓ page_fault_common(regs, error_code, read_cr2()) ↓ handle_page_fault() 或 do_user_addr_fault() / do_kern_addr_fault()
read_cr2()用于获取触发异常的地址,因为缺页异常的错误码中不包含地址信息,必须从 CR2 寄存器读取。