使用OHCI-1394 FireWire控制器提供的物理DMA进行调试

简介

目前使用的几乎所有FireWire控制器都符合OHCI-1394规范。该规范将控制器定义为PCI总线主控器,它使用DMA将数据传输从CPU卸载,并拥有一个“物理响应单元”,该单元在应用OHCI-1394驱动程序定义的过滤器后,通过使用PCI总线主控DMA执行特定请求。

一旦正确配置,远程机器可以发送这些请求,要求OHCI-1394控制器对物理系统内存执行读写请求,对于读请求,将物理内存读取的结果发送回请求者。

通过这种方式,可以通过读取如printk缓冲区或进程表等感兴趣的内存位置来调试问题。

通过FireWire,也可以获取完整的系统内存转储,数据传输速率可达10MB/秒或更高。

对于大多数FireWire控制器,内存访问限于物理地址空间的低4 GB。这在内存主要位于该限制之上的机器上可能是一个问题,但在x86、x86-64和PowerPC等更常见的硬件上,这很少是一个问题。

已知LSI FW643e和FW643e2控制器至少支持访问4 GB以上的物理地址,但此功能目前尚未被Linux启用。

结合OHCI-1394控制器早期用于调试的初始化,此功能在检查printk缓冲区中的长调试日志、调试ACPI等系统无法启动的早期启动问题时非常有用,因为其他调试方式(串行端口)要么不可用(笔记本电脑),要么对于大量调试信息(如ACPI)来说太慢。

驱动程序

drivers/firewire 中的 firewire-ohci 驱动程序默认使用过滤的物理DMA,这更安全但不适合远程调试。向驱动程序传递 remote_dma=1 参数以获取未过滤的物理DMA。

由于firewire-ohci驱动程序依赖于PCI枚举完成,因此为x86实现了一个运行非常早的初始化例程。此例程在console_init()可以被调用之前很久就运行了,即在printk缓冲区出现在控制台之前。

要激活它,请启用 CONFIG_PROVIDE_OHCI1394_DMA_INIT(内核开发菜单:通过FireWire在启动早期进行远程调试),并在启动时将参数“ohci1394_dma=early”传递给重新编译的内核。

工具

firescope - 最初由Benjamin Herrenschmidt开发,Andi Kleen将其从PowerPC移植到x86和x86_64并增加了功能,firescope现在可以用来查看远程机器的printk缓冲区,甚至可以进行实时更新。

Bernhard Kaindl增强了firescope,使其支持从32位firescope访问64位机器,反之亦然:- http://v3.sk/~lkundrak/firescope/

并且他实现了快速系统转储(alpha版本 - 阅读README.txt):- http://halobates.de/firewire/firedump-0.1.tar.bz2

还有一个FireWire的gdb代理,它允许使用gdb访问vmlinux中gdb找到的符号可以引用的数据:- http://halobates.de/firewire/fireproxy-0.33.tar.bz2

这个gdb代理的最新版本(fireproxy-0.34)可以通过基于内存的通信模块(kgdbom)与kgdb通信(尚未稳定)。

入门

OHCI-1394规范规定OHCI-1394控制器在每次总线复位时必须禁用所有物理DMA。

这意味着,如果您想在中断被禁用且OHCI-1394控制器未进行总线复位轮询的系统状态下调试问题,您必须在系统进入该状态__之前__建立所有FireWire电缆连接并完全初始化所有FireWire硬件。

使用早期OHCI初始化使用firescope的分步说明

  1. 验证您的硬件是否受支持

    加载firewire-ohci模块并检查您的内核日志。您应该看到类似以下内容的行:

    firewire_ohci 0000:15:00.1: added OHCI v1.0 device as card 2, 4 IR + 4 IT
    ... contexts, quirks 0x11
    

    加载驱动程序时。如果您没有受支持的控制器,市面上有许多完全符合OHCI-1394规范的PCI、CardBus甚至某些Express卡可用。如果它不需要Windows操作系统的驱动程序,那么它很可能就是兼容的。只有专门的商店才有不兼容的卡,它们基于TI PCILynx芯片,需要Windows操作系统的驱动程序。

    如果控制器实现了可写的物理上限(Physical Upper Bound)寄存器,则上述内核日志消息会包含字符串“physUB”。这是4 GB以上物理DMA所需的(但Linux尚未利用此功能)。

  2. 建立一个工作的FireWire电缆连接

    任何FireWire电缆都可以,只要它能提供电气和机械上稳定的连接,并且连接器匹配(有小的4针和大的6针FireWire端口)。

    如果两台机器上都运行着驱动程序,那么当电缆插入并连接两台机器时,您应该在两台机器的内核日志中看到类似以下内容的行:

    firewire_core 0000:15:00.1: created device fw1: GUID 00061b0020105917, S400
    

    当电缆插入并连接两台机器时,两台机器的内核日志中都会出现。

  3. 使用firescope测试物理DMA

    在调试主机上,确保/dev/fw*可访问,然后启动firescope

        $ firescope
        Port 0 (/dev/fw1) opened, 2 nodes detected
    
        FireScope
        ---------
        Target : <unspecified>
        Gen    : 1
        [Ctrl-T] choose target
        [Ctrl-H] this menu
        [Ctrl-Q] quit
    
    ------> Press Ctrl-T now, the output should be similar to:
    
        2 nodes available, local node is: 0
         0: ffc0, uuid: 00000000 00000000 [LOCAL]
         1: ffc1, uuid: 00279000 ba4bb801
    

    除了[LOCAL]节点外,它还必须显示另一个没有错误消息的节点。

  4. 准备使用早期OHCI-1394初始化进行调试

    4.1) 在调试目标上编译和安装内核

    使用启用了CONFIG_PROVIDE_OHCI1394_DMA_INIT(内核开发:提供在启动早期通过FireWire启用DMA的代码)的内核进行编译,并将其安装到被调试机器(调试目标)上。

    4.2) 将被调试内核的System.map传输到调试主机

    将被调试内核的System.map复制到调试主机(通过FireWire电缆连接到被调试机器的主机)上。

  5. 获取printk缓冲区内容

    连接好FireWire电缆,在调试主机上加载OHCI-1394驱动程序后,重新启动被调试机器,启动已启用CONFIG_PROVIDE_OHCI1394_DMA_INIT选项的内核,并带有 ohci1394_dma=early 参数。

    然后,在调试主机上运行firescope,例如使用-A参数

    firescope -A System.map-of-debug-target-kernel
    

    注意:-A会自动附加到第一个非本地节点。它仅在仅有两台机器通过FireWire连接时才能可靠工作。

    附加到调试目标后,按Ctrl-D查看完整的printk缓冲区,或按Ctrl-U进入自动更新模式,以获取调试目标上最新内核消息的实时更新视图。

    调用“firescope -h”以获取更多关于firescope选项的信息。

备注

文档和规范:http://halobates.de/firewire/

FireWire是Apple Inc.的商标 - 更多信息请参阅:https://en.wikipedia.org/wiki/FireWire