Linux kernel 如何调试pci设备和linux驱动程序

Linux kernel 如何调试pci设备和linux驱动程序,linux-kernel,kernel,linux-device-driver,kernel-module,pci-e,Linux Kernel,Kernel,Linux Device Driver,Kernel Module,Pci E,我正在用verilog编程一个pci设备并编写它的驱动程序, 我可能在硬件设计中插入了一些bug,当我用insmod加载驱动程序时,内核就卡住了,没有响应。现在我正试图找出最后一个让我的电脑卡住的驱动程序代码行是什么。我已经在所有相关函数中插入了printk,比如probe和init,但是没有一个函数被打印出来 在insmod到达init函数之前使用insmod时,还有什么代码正在运行?(我猜内核会卡在那里)我会在总线上安装一个逻辑分析仪(在FPGA上,您可以使用chipscope或类似产品)。

我正在用verilog编程一个pci设备并编写它的驱动程序, 我可能在硬件设计中插入了一些bug,当我用insmod加载驱动程序时,内核就卡住了,没有响应。现在我正试图找出最后一个让我的电脑卡住的驱动程序代码行是什么。我已经在所有相关函数中插入了printk,比如probe和init,但是没有一个函数被打印出来


在insmod到达init函数之前使用insmod时,还有什么代码正在运行?(我猜内核会卡在那里)

我会在总线上安装一个逻辑分析仪(在FPGA上,您可以使用chipscope或类似产品)。然后,您将能够判断导致访问的原因(并修复硬件)。无论如何,为了调试或分析将来的问题,它都是有用的


另一种方法是使用内核崩溃转储实用程序,这在过去帮我省去了一些麻烦。但根据您的Linux发行版,需要安装(默认情况下在RH中提供)。请参见

在初始化之前,实际上没有运行任何东西。总线枚举是在引导时完成的,如果这一切顺利进行,那么冻结的最早原因应该是驱动程序init AFAIK中的某些内容

您应该能够在打印时看到
printk
s,它们不会被缓冲,也不会丢失。这仅适用于可以直接看到内核输出的情况,例如在文本控制台上或通过串行线。如果还有其他应用程序,比如在X11或ssh上的终端中显示内核日志,那么在计算机冻结之前,它可能没有机会读取和显示日志

如果由于某些其他原因,
printk
s仍然不适用于您,您可以让init函数提前返回。只需在init中测试并将返回移动到后面的位置,直到找到它崩溃的点

很难说是什么导致了你的冻结,但中断是我首先要看的事情之一。确保设备在驱动程序启用中断(包括在系统重置时清除中断启用)之前不会发出中断信号,并且只有在所有处理程序注册后才在驱动程序中启用中断(同样,在启用中断之前清除中断状态)


第二件要看的是公交主换乘,同样的事情也适用:确保设备在被要求之前不会执行任何操作,并让驱动程序确保在设备级别启用总线主控传输之前没有总线主控传输处于活动状态。

一旦安装驱动程序模块,内核就会卡滞,这一事实让我怀疑是否还有其他驱动程序(内置到内核中?)正在驱动设备。我曾经犯过这个错误,这就是为什么我要问这个问题。在安装模块之前,我会在'lspci'的输出中查找字符串“kerneldriver in use”。在任何情况下,您的printk都应该在dmesg输出中可见。

除了Claudio的建议之外,还有一些调试想法: 1.试试kgdb()
2.使用JTAG接口连接到调试工具(我认为这些工具因设备、供应商而异,因此您必须确定特定硬件需要哪些调试工具)

printk
s通常在调试此类问题时没有用。如果调用
printk
后不久系统挂起,它们将得到充分的缓冲,您将无法及时看到它们

有选择地注释掉驱动程序的各个部分,并通过排除过程确定哪一行是(第一个)问题,效率要高得多


首先注释掉整个模块的
init
部分,只留下
返回0。构建并加载它。它挂起来了吗?重新启动系统,重新启动接下来的几行(
class_create()
?)并重复。

从您所说的,看起来Linux调度程序被您的驱动程序死锁了。这意味着来自系统计时器的中断不会到达,也没有机会被内核处理。可能有两个原因:

  • 您挂在驱动程序中断处理程序的某个地方(处理程序开始工作,但从未完成)
  • 您的设备会造成中断风暴(设备产生中断的频率太高,导致您的系统只负责处理设备中断)
  • 您显式禁用驱动程序中的所有中断,但不重新启用它们
在所有其他情况下,系统将崩溃、oops或所有适当的输出死机,或者容忍设备的潜在错误行为

我想,
printk
对于挂起内核模式这样的极端场景是不起作用的。这是相当重的重量,由于这种不可靠的诊断工具的情况下,如您的。 这个技巧只适用于更简单的环境,如引导加载程序或更简单的内核,其中系统以默认的低端视频模式运行,并且不需要同步访问视频内存。在这样的系统中,通过直接写入视频内存将输出调试到显示器进行跟踪是非常好的,并且在很多情况下是唯一可用于调试目的的工具。Linux并非如此

从软件调试的角度来看,可以推荐哪些技术:

  • 试着查看驱动程序代码,特别注意中断处理程序和禁用/启用中断以进行同步的位置
  • 在所有驱动程序逻辑之外进行注释,并逐渐取消注释,这对问题的本地化有很大帮助
  • 您可以尝试使用驱动程序的远程内核调试。我建议尝试使用虚拟机来实现这一目的,但我不知道它们是否允许在虚拟机中传递PCI设备
  • 您可以尝试内存跟踪的技巧。其思想是使用已知的虚拟和物理地址预先分配内存块并将其归零。然后修改驱动程序,使用其虚拟地址在该块中写入跟踪数据。(例如