我仿照着写了一个,名为my_page_fault:
|
其中第9行addr_adjust_exception_frame是(pv_irq_ops+0x30)地址处存储的值;第11行addr_error_entry是error_entry的地址;第16行addr_error_exit是error_exit的地址。这几个值需要从System.map文件中查询,然后用内核模块参数的形式传入。而my_do_page_fault则是我们自己定义的page fault处理函数。
如果需要截获X86_32的page fault,可以参考这个C文件。不过需要注意的是,新版内核有所变动,这里的代码需要根据自己的情况做一些调整。
有了自定义的ISR之后,就可以将这个ISR填到IDT中,加载新的IDT表之后,自定义的page fault处理函数就开始发挥作用了。这个过程主要有以下几个步骤:
用store_idt(&default_idtr)保存现有的IDT寄存器值
从default_idtr中读出IDT表首地址和表的大小
申请一个页面
将原来的idt表拷贝到新申请的页面中
利用pack_gate将my_page_fault(注意不是my_do_page_fault)填入到对应的IDT项中
在idtr中填写新的IDT表地址和大小,用load_idt(&idtr)加载新的IDT表到当前CPU
利用smp_call_function,将新的IDT表加载到其他CPU上。
如果想恢复原来的IDT表,则用load(&default_idtr)和smp_call_function加载原来的IDT表,释放申请的页面。
读完文章之后,可以参考我的github中的代码:https://github.com/RichardUSTC/intercept-page-fault-handler