1

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

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

4

6 回答 6

2

printks 调试这样的问题往往没用。printk它们被充分缓冲,如果系统在调用后不久挂起,您将无法及时看到它们。

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

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

于 2014-04-29T19:34:01.157 回答
1

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

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

在所有其他情况下,系统要么崩溃,要么在所有适当的输出时出现 oops 或恐慌,要么容忍设备的潜在不当行为。

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

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

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

一般来说,内核调试是一项非常棘手的任务,其中使用了很多技巧,而且它们都只适用于特定的情况。:(

于 2015-09-03T03:59:22.490 回答
0

我会在总线上放置一个逻辑分析仪(在 FPGA 上,您可以使用芯片示波器或类似设备)。然后,您将能够判断是哪个访问导致(并修复硬件)。无论如何,它对于调试或分析未来的问题都会很有用。

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

于 2014-04-06T18:25:23.480 回答
0

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

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

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

很难说是什么导致了你的卡顿,但中断是我首先要考虑的事情之一。确保设备在驱动程序启用它们之前确实不会发出中断信号(包括在系统复位时清除中断启用),并且只有在所有处理程序都注册后才在驱动程序中启用它们(另外,在启用中断之前清除中断状态)。

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

于 2014-04-06T23:02:40.417 回答
0

一旦安装驱动程序模块,内核就会卡住,这让我想知道是否有任何其他驱动程序(内置于内核?)已经在驱动设备。我曾经犯过这个错误,这就是我问的原因。在安装模块之前,我会在“lspci”的输出中查找字符串“正在使用的内核驱动程序”。在任何情况下,您的 printk 都应该在 dmesg 输出中可见。

于 2014-04-07T04:47:27.200 回答
0

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

于 2014-04-08T01:38:22.493 回答