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

时间:2014-04-06 09:04:33

标签: linux-kernel kernel linux-device-driver kernel-module pci-e

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

当我使用insmod进入我的init函数之前还运行了什么其他代码? (我猜内核会卡在那里)

6 个答案:

答案 0 :(得分:1)

printk通常无法解决此类问题。它们被充分缓冲,如果在调用printk后系统挂起,您将无法及时看到它们。

选择性地注释掉驱动程序的各个部分并通过消除过程确定哪一行是(第一个)问题会更有效率。

首先评论整个模块的init部分,只留下return 0;。构建并加载它。它挂了吗?重新启动系统,重新启用接下来的几行(class_create()?)并重复。

答案 1 :(得分:1)

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

  • 你挂在驱动程序中断处理程序中的某个地方(处理程序启动它的工作但从未完成它)。
  • 您的设备会产生中断风暴(设备会过于频繁地生成中断,因此系统会执行唯一的工作 - 处理设备中断)。
  • 您明确禁用了驱动程序中的所有中断,但没有重新启用它们。

在所有其他情况下,系统会崩溃,无论是oops还是恐慌都会带有所有适当的输出,或者容忍设备潜在的不当行为。

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

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

  1. 尝试检查驱动程序代码,特别注意中断处理程序以及禁用/启用中断以进行同步的位置。
  2. 通过逐步取消注释来评论所有驱动程序逻辑可以帮助解决问题的本地化。
  3. 您可以尝试使用驱动程序的远程内核调试。我建议尝试使用虚拟机,但我不知道他们是否允许在虚拟机中传递PCI设备。
  4. 你可以尝试使用内存中的跟踪技巧。我们的想法是使用众所周知的虚拟和物理地址预分配内存块并将其归零。然后修改驱动程序,使用其虚拟地址在此块中写入跟踪数据。 (例如,为要跟踪的每个事件分配一个唯一的整数值,并将其写入预分配的存储单元中的相应的字节数组索引中)。然后,当您的系统挂起时,您可以简单地强制完全内存转储生成,然后使用带有跟踪的内存块的物理地址分析转储中打包的内存布局。我在Windows上使用这种技术与VmWare Workstation VM。当系统挂起时,我只是暂停一个VM实例并查看相应的.vmem文件,该文件包含VM实例的物理内存的原始内存latout。不确定这个技巧是否会起作用,甚至可以在Linux上运行,但我会尝试一下。
  5. 最后,您可以尝试跟踪PCI总线上的消息,但我不是该领域的专家,并且不确定它是否可以帮助您。
  6. 一般情况下,内核调试是一项非常棘手的任务,其中使用了很多技巧,所有这些技巧仅适用于特定的一组案例。 :(

答案 2 :(得分:0)

我会在总线上放置一个逻辑分析仪(在FPGA上你可以使用chipcope或类似的)。然后,您将能够分辨出哪种访问原因(并修复硬件)。无论如何,它将是有用的,以便调试或分析未来的问题。

另一种方法是使用内核崩溃转储实用程序,这在过去让我有些头疼。但是,根据您的Linux发行版需要安装(默认情况下在RH中可用)。见http://people.redhat.com/anderson/crash_whitepaper/

答案 3 :(得分:0)

在你的init之前没有任何东西可以运行。总线枚举是在启动时完成的,如果顺利完成,最早的冻结原因应该是您的驱动程序init AFAIK中的内容。

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

如果由于某些其他原因导致printk仍然无法正常工作,则可以提前返回初始化函数。只需测试并将返回值移至init中,直到找到崩溃点为止。

很难说是什么导致你的冻结,但中断是我首先要看的东西之一。确保设备确实不会发出中断信号,直到驱动程序启用它们(包括清除中断使能系统复位),并且只有在所有处理程序都被注册后才能在驱动程序中启用它们(同样,在启用中断之前清除中断状态)。

要看的第二件事是总线主传输,同样的事情适用:确保设备没有做任何事情,直到它被要求并让驱动程序确保没有总线传输之前有效在设备级别启用busmastering。

答案 4 :(得分:0)

安装驱动程序模块后内核卡住的事实让我想知道是否有其他驱动程序(内置于内核?)已经在驱动设备。我犯了这个错误,这就是我要问的原因。我正在寻找正在使用的字符串"内核驱动程序"在< lspci'的输出中在安装模块之前。无论如何,你的printk应该在dmesg输出中可见。

答案 5 :(得分:0)

除了克劳迪奥的建议外,还有更多的调试思路: 1.尝试kgdb(https://www.kernel.org/doc/htmldocs/kgdb/EnableKGDB.html) 2.使用JTAG接口连接到调试工具(我认为这些设备因供应商而异,因此您必须弄清楚特定硬件需要哪些调试工具)