Linux kernel 在简单的IRQ处理程序中调用printk会导致内核崩溃

Linux kernel 在简单的IRQ处理程序中调用printk会导致内核崩溃,linux-kernel,x86-64,irq,isr,page-fault,Linux Kernel,X86 64,Irq,Isr,Page Fault,我是内核编程新手,我找不到足够的信息来知道为什么会发生这种情况。基本上,我试图用一些简单的方法来替换内核IDT中的页面错误处理程序,这些方法最终调用原始处理程序。我只想让这个函数打印一个调用它的通知,在它内部调用printk()总是会导致内核死机。否则就没问题了 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #定义PAGEFAULT_索引14 //新旧IDT寄存器 静态结构描述旧的idt注册,新的idt注册; 静态uuu属性uuu((uuu使用的uuu)

我是内核编程新手,我找不到足够的信息来知道为什么会发生这种情况。基本上,我试图用一些简单的方法来替换内核IDT中的页面错误处理程序,这些方法最终调用原始处理程序。我只想让这个函数打印一个调用它的通知,在它内部调用
printk()
总是会导致内核死机。否则就没问题了

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义PAGEFAULT_索引14
//新旧IDT寄存器
静态结构描述旧的idt注册,新的idt注册;
静态uuu属性uuu((uuu使用的uuu))无符号长旧页面错误指针,新页面;
//替换原始处理程序的函数
ASM链接无效isr_页面故障(无效);
asm(“文本”);
asm(“.type isr_pagefault,@function”);
asm(“isr_pagefault:”);
asm(“呼叫打印某物”);
asm(“jmp*旧页面错误指针”);
作废打印某物(作废){
//这个printk导致内核崩溃!
printk(KERN_ALERT“页面错误处理程序被调用\n”);
返回;
}
作废我的ID加载(作废*ptr){
printk(KERN_警报“加载到新处理器…\n”);
加载idt((结构描述ptr*)ptr);
返回;
}
int模块_开始(无效){
门描述*旧地址,*新地址;
无符号长idt_长度;
存储标识(&old\u idt\u reg);
旧idt地址=(门描述*)旧idt注册地址;
idt_长度=旧idt_注册尺寸;
//从IDT的pagefault条目获取pagefault处理程序指针
旧页面错误指针=0

|((unsigned long)(old_idt_addr[PAGEFAULT_INDEX]。offset_high)为什么要尝试替换页面错误处理程序?如果要跟踪页面错误,方法是使用kprobe

至于手头的问题,这里可能没有什么神秘的东西,尽管你没有展示崩溃的样子。很可能你在用户空间中出现了页面错误,但这意味着gs包含用户空间垃圾,而不是每个cpu的内核数据。据推测,它会在以后被访问,并且不会很好地结束。所有内核入口点都包括swapgs。

一般来说,安装自己的处理程序意味着您必须正确地获取大量的级别信息。我看不出任何原因,您正在使其变得困难

我们来看看,

crash> dis page_fault
0xffffffffbb804da0 <page_fault>:        data32 xchg %ax,%ax
0xffffffffbb804da3 <page_fault+3>:      data32 xchg %ax,%ax
0xffffffffbb804da6 <page_fault+6>:      data32 xchg %ax,%ax
0xffffffffbb804da9 <page_fault+9>:      add    $0xffffffffffffff88,%rsp
0xffffffffbb804dad <page_fault+13>:     callq  0xffffffffbb804f30 <error_entry>
0xffffffffbb804db2 <page_fault+18>:     mov    %rsp,%rdi
0xffffffffbb804db5 <page_fault+21>:     mov    0x78(%rsp),%rsi
0xffffffffbb804dba <page_fault+26>:     movq   $0xffffffffffffffff,0x78(%rsp)
0xffffffffbb804dc3 <page_fault+35>:     callq  0xffffffffbb062840 <do_page_fault>
0xffffffffbb804dc8 <page_fault+40>:     jmpq   0xffffffffbb804ff0 <error_exit>
0xffffffffbb804dcd <page_fault+45>:     nopl   (%rax)


crash> dis error_entry
0xffffffffbb804f30 <error_entry>:       cld    
0xffffffffbb804f31 <error_entry+1>:     mov    %r11,0x38(%rsp)
0xffffffffbb804f36 <error_entry+6>:     mov    %r10,0x40(%rsp)
0xffffffffbb804f3b <error_entry+11>:    mov    %r9,0x48(%rsp)
0xffffffffbb804f40 <error_entry+16>:    mov    %r8,0x50(%rsp)
0xffffffffbb804f45 <error_entry+21>:    mov    %rax,0x58(%rsp)
0xffffffffbb804f4a <error_entry+26>:    mov    %rcx,0x60(%rsp)
0xffffffffbb804f4f <error_entry+31>:    mov    %rdx,0x68(%rsp)
0xffffffffbb804f54 <error_entry+36>:    mov    %rsi,0x70(%rsp)
0xffffffffbb804f59 <error_entry+41>:    mov    %rdi,0x78(%rsp)
0xffffffffbb804f5e <error_entry+46>:    mov    %r15,0x8(%rsp)
0xffffffffbb804f63 <error_entry+51>:    mov    %r14,0x10(%rsp)
0xffffffffbb804f68 <error_entry+56>:    mov    %r13,0x18(%rsp)
0xffffffffbb804f6d <error_entry+61>:    mov    %r12,0x20(%rsp)
0xffffffffbb804f72 <error_entry+66>:    mov    %rbp,0x28(%rsp)
0xffffffffbb804f77 <error_entry+71>:    mov    %rbx,0x30(%rsp)
0xffffffffbb804f7c <error_entry+76>:    xor    %ebx,%ebx
0xffffffffbb804f7e <error_entry+78>:    testb  $0x3,0x90(%rsp)
0xffffffffbb804f86 <error_entry+86>:    je     0xffffffffbb804f9a <error_entry+106>
0xffffffffbb804f88 <error_entry+88>:    swapgs 
crash>dis页面故障
0xFFFFFFBB804DA0:data32 xchg%ax,%ax
0xFFFFFFBB804DA3:data32 xchg%ax,%ax
0xFFFFFFBB804DA6:data32 xchg%ax,%ax
0xFFFFFFBB804DA9:添加$0xFFFFFFFFFFFF88,%rsp
0xFFFFFFBB804DAD:callq 0xffffffffbb804f30
0xFFFFBB804DB2:mov%rsp%rdi
0xFFFFFFBB804DB5:mov 0x78(%rsp),%rsi
0xFFFFFFBB804DBA:movq$0xffffffffffffffff,0x78(%rsp)
0xFFFFFFBB804DC3:callq 0xffffffffbb062840
0xFFFFFFBB804DC8:jmpq 0xffffffffbb804ff0
0xFFFFBB804DCD:nopl(%rax)
崩溃>dis错误\u条目
0xFFFFBB804F30:cld
0xFFFFBB804F31:mov%r11,0x38(%rsp)
0xFFFFBB804F36:mov%r10,0x40(%rsp)
0xFFFFBB804F3B:mov%r9,0x48(%rsp)
0xFFFFBB804F40:mov%r8,0x50(%rsp)
0xFFFFBB804F45:mov%rax,0x58(%rsp)
0xFFFFBB804F4A:mov%rcx,0x60(%rsp)
0xFFFFBB804F4F:mov%rdx,0x68(%rsp)
0xFFFFBB804F54:mov%rsi,0x70(%rsp)
0xFFFFBB804F59:mov%rdi,0x78(%rsp)
0xFFFFBB804F5E:mov%r15,0x8(%rsp)
0xFFFFBB804F63:mov%r14,0x10(%rsp)
0xFFFFFFBB804F68:mov%r13,0x18(%rsp)
0xFFFFBB804F6D:mov%r12,0x20(%rsp)
0xFFFFBB804F72:mov%rbp,0x28(%rsp)
0xFFFFBB804F77:mov%rbx,0x30(%rsp)
0xFFFFFFBB804F7C:xor%ebx,%ebx
0xFFFFFFBB804F7E:testb$0x3,0x90(%rsp)
0xFFFFFFBB804F86:je 0xffffffffbb804f9a
0xFFFFBB804F88:swapgs
就在那里

0xffffffffbb804f8b <error_entry+91>:    data32 xchg %ax,%ax
0xffffffffbb804f8e <error_entry+94>:    jmpq   0xffffffffbb804f98 <error_entry+104>
0xffffffbb804f8b:data32 xchg%ax,%ax
0xFFFFFFBB804F8E:jmpq 0xffffffffbb804f98

也就是说,你为什么要玩这些东西呢?我强烈建议现在在用户空间中使用一些程序集。

据我所知,printk()比ftrace需要更多的资源和复杂性(控制台/文件系统/存储)。 如果崩溃只发生在使用printk()的情况下,为什么不使用ftrace而不是printk()


许多Linux内核专家都喜欢ftrace。

很抱歉,这是一篇死信,但只为子孙后代着想:

我在挂接IDT条目时遇到过类似的问题;一种可能是堆栈空间不足。在64位模式下,当调用陷阱或故障处理程序时,CPU会根据“中断堆栈表”(IST)确定新的堆栈指针相应中断描述符的字段–位32到34–以及处理器核心的任务状态段(
TSS
)。摘自《英特尔软件开发人员手册》第3A卷第6.14.5节:

在IA-32e模式下,新的中断堆栈表(IST)该机制可用作上述修改后的传统堆栈切换机制的替代。该机制在启用时无条件切换堆栈。可以使用IDT条目中的字段在单个中断向量的基础上启用该机制。这意味着某些中断向量可以使用修改后的传统机制和othER可以使用IST机制

IST机制仅在IA-32e模式下可用。它是64位模式TSS的一部分。IST机制的动机是为特定中断(如NMI、双重故障和机器检查)提供一种方法始终在已知良好堆栈上执行。在传统模式下,中断可以使用任务切换机制通过位于IDT中的任务门访问中断服务例程来设置已知良好堆栈。但是,IA-32e模式不支持传统任务切换机制

IST机制在TSS中提供多达七个IST指针。这些指针由interrup中的中断门描述符引用