OS 尝试访问 PCI 内存映射寄存器时 X 内核崩溃

OS X kernel panic when attempting to access PCI memory-mapped register

我指的代码是 here

当我为 pcidevice 创建内存映射时,我总是得到相同的 getPhysicalAddressgetVirtualAddress 值: 例如

pciDevice = OSDynamicCast(IOPCIDevice, provider);
deviceMap = pciDevice->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0);

deviceRegisters = (struct oxygen *)  deviceMap->getVirtualAddress();
pciDevice->setMemoryEnable(true);
pciDevice->setBusMasterEnable(true);
deviceMap->getPhysicalAddress();

现在,其实,我对此并不太惊讶,因为我认为这就是“DMA”的意义所在。

这个理解正确吗?

现在主要问题是:我遇到了由 deviceRegisters 成员的任何访问或分配引起的内核恐慌,例如:

kprintf("Xonar Vendor ID:0x%04x, Device ID:0x%04x, SubDevice ID:0x%04x, Physical Address:%lu\n",
       vendor_id, dev_id, subdev_id, deviceRegisters->addr);

现在这告诉我我在分配方面做错了什么,因为访问这个结构的成员不应该引起恐慌。

但是,如果您在此处查看清单 3-2:https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/WritingAudioDrivers/ImplementDriver/ImplementDriver.html#//apple_ref/doc/uid/TP30000732-DontLinkElementID_15

这正是应该如何完成的。

一位智者 (pmj) 建议我必须使用 ioRead/Write 函数来 assign/access 这些值,但这与 apple 提供的(公认的旧)骨架代码并不相符。什么会导致对此内存映射的访问问题?当然必须对 assign/read 值进行指针运算,虽然可能是正确的,但这不是此设计的目的吗?

when i create a memory mapping for a pcidevice, i am always getting the same value for getPhysicalAddress and getVirtualAddress: e.g.

这些值是否在 0x0..0xffff 范围内?

我非常怀疑这是一个 port-mapped I/O range in your PCI device,而不是内存映射范围。

在您的代码中检查这一点的方法是:

if (0 != (kIOPCIIOSpace & pciDevice->configRead32(kIOPCIConfigBaseAddress0))
{
    // port mapped range
}
else
{
    // memory mapped range
}

另请参阅:

now, actually, i’m not too surprised by this because i think this is the point of “DMA”.

不,端口映射 I/O 与 DMA 几乎相反。如果您的设备碰巧是这样操作的,您当然可以使用端口映射 I/O 来启动 DMA 传输,因此也许最好将其表述为与 DMA 正交。

DMA 是关于直接访问系统内存的设备。 PCI BAR 是关于 CPU 访问设备寄存器或内存的。

if we have some kind of mapping in the driver, then one is all we need. that is, the physicaladdress is the virtual address as it’s the sole spot we need to do the “memory to memory” (cpu datastore to PCI sound card) is this understanding correct?

不行,至少在x86上,I/O端口地址space与物理内存地址space是完全分开的,因此也不能映射到虚拟地址space,因为 MMU 在虚拟和物理 内存 space 之间转换。在 x86 上,有特殊的机器指令,inout,用于从 I/O 端口读取和写入。然而,在大多数架构上(对于 OS X,尤其是 PPC,但我认为 ARM 也是如此),存在某种形式的内存映射。我不知道它是如何在这些架构上详细工作的,但是为了这个问题的目的,你真的不需要关心:

在 macOS kext 中的端口映射范围上执行 I/O 的独立于架构的方法是在 ioread*iowrite* 上使用方法=16=],其中 * 可以是 81632,用于 PCI 标准允许的 3 种不同的可能 I/O 字长。

now for the main issue: i am experiencing kernel panics that are caused caused by any access or assignment of deviceRegisters’ members, such as:

假设您实际上正在处理设备中的端口映射 I/O 范围,那么这就解释了您的内核恐慌。使用 pciDevice->ioread16(register_offset, deviceMap) 或类似的。

a wise man (pmj) suggested i must use ioRead/Write functions to assign/access these values, but this does not really jive with the (admittedly old) skeleton code provided by apple.

您链接到的文档假定设备的 BAR 指的是内存映射范围,而不是端口映射 I/O 范围。