我指的是here
当我为pcidevice创建内存映射时,我总是为getPhysicalAddress和getVirtualAddress获得相同的值:例如
pciDevice = OSDynamicCast(IOPCIDevice, provider); deviceMap = pciDevice->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0); deviceRegisters = (struct oxygen *) deviceMap->getVirtualAddress(); pciDevice->setMemoryEnable(true); pciDevice->setBusMasterEnable(true); deviceMap->getPhysicalAddress();
现在,实际上,我对此并不感到惊讶,因为我认为这就是“ DMA”的意义。
- 即物理地址是虚拟地址,因为它是我们要做“内存到内存”(cpu数据存储到PCI声卡)的唯一位置]
这种理解正确吗?
现在是主要问题:我正在遇到由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);
现在告诉我某些事情,我在分配方面做错了,因为访问此结构的成员不会引起恐慌。
这正是应该完成的方式。
一个聪明的人(pmj)建议我必须使用ioRead / Write函数来分配/访问这些值,但这与Apple提供的(被认为是很旧的)框架代码并不一致。什么会导致对此内存映射的访问问题?当然必须做指针算术来分配/读取值,尽管可能正确,但这不是设计的目的吗?
[当我为pcidevice创建内存映射时,我总是为getPhysicalAddress和getVirtualAddress获得相同的值:例如
这些值是否在0x0..0xffff
范围内?
我非常怀疑这是一个port-mapped I/O range in your PCI device,而不是内存映射范围。
在您的代码中检查此方法的方式是:
if (0 != (kIOPCIIOSpace & pciDevice->configRead32(kIOPCIConfigBaseAddress0))
{
// port mapped range
}
else
{
// memory mapped range
}
另请参见:https://stackoverflow.com/a/44352611/48660
现在,实际上,我对此并不感到惊讶,因为我认为这就是“ DMA”的意义。
不,端口映射的I / O与DMA相反。如果您的设备恰好可以运行,那么您当然可以使用端口映射的I / O发起DMA传输,因此最好将其表述为与DMA正交。
DMA与设备直接访问系统内存有关。 PCI BAR与CPU访问设备寄存器或内存有关。
如果驱动程序中有某种映射,那么就是我们所需要的。也就是说,物理地址是虚拟地址,因为它是我们要做“内存到内存”(CPU数据存储到PCI声卡)的唯一位置这种理解正确吗?
否,至少在x86上,I / O端口地址空间与物理内存地址空间完全分开,因此,由于MMU在虚拟和物理内存之间进行转换,因此也无法映射到虚拟地址空间。 空格。在x86上,有特殊的机器指令in
和out
,用于从I / O端口读取和写入。但是,在大多数体系结构(对于OS X尤其是PPC)上,存在某种形式的内存映射。
在macOS kext中,与体系结构无关的方法是在ioread*
上使用iowrite*
和IOPCIDevice
方法,其中*
可以是8
,16
或32
PCI标准允许的3种不同的I / O字长。
现在是主要问题:我正在遇到由deviceRegisters成员的任何访问或分配引起的内核恐慌,例如:
假设您实际上正在处理设备中的端口映射I / O范围,那么这说明了您的内核崩溃。使用pciDevice->ioread16(register_offset, deviceMap)
或类似名称。
一个聪明的人(pmj)建议我必须使用ioRead / Write函数来分配/访问这些值,但这与Apple提供的(被认为是很旧的)框架代码并不一致。
链接到的文档假定设备的BAR是指内存映射范围,而不是端口映射的I / O范围。