我有 2 个与 PCI 总线相关的问题:
设备驱动程序如何访问 PCI 总线上的设备?写入为设备分配的内存区域是否足够(mov memory_space_allocated_for_dev, something如果设备是内存映射的,或者out io_space_allocated for_dev, something如果不是)(硬件会将这种访问内存位置的尝试转换为 PCI 总线上的一系列 PCI 命令等?)。
在所有 PCI 总线上设置所有设备(即分配内存空间、枚举总线等)之后,设备驱动程序不必知道 PCI 总线是否存在或内存解码是通过简单的解码器完成的(就像在旧计算机中一样)是否正确? )(即他们只是简单地从某些内存位置写入和读取以访问设备)?
内存映射 PCI(e) 设备将具有 BAR(基地址寄存器),让主机知道应该为设备分配多少内存。BIOS(以及以后的操作系统)会将请求的内存空间分配给目标设备——不是说它是内存地址,而是没有分配物理位。此外,这通常是物理内存地址,而不是虚拟内存地址。Linux 内核将使用 mmap() 等函数仲裁对这些设备的访问,这些函数允许将物理内存映射到虚拟内存地址。
例如,假设您有一个控制 8 个 LED 的 PCIe 设备。作为设备创建者,我可以请求一个非常小的 1K 地址空间的 BAR。BIOS 可能会在 0xE000_0000 到 0xE000_0400 的 32 位系统上为我提供物理地址(旁注:您现在应该在这里看到为什么 32 位系统和具有大 VRAM 的 GPU 不能很好地协同工作)。
现在,如果我用一字节写入将 0xF0 写入内存位置 0xE000_0000,这将打开 LED 7 到 4,并使 3 到 0 关闭。就是这样——它是简单的内存映射 I/O。添加抽象层,在 Linux 上,您将利用其出色的 PCI 子系统并编写一个驱动程序,为给定的供应商 ID + 设备 ID 字符串加载。然后,您可以编写一个调用该内核驱动程序的用户空间应用程序,其中 mmap() 调用可以将内存映射到用户空间,从而允许您的用户空间应用程序对某些虚拟内存地址进行字节读取/写入,这些虚拟内存地址将被转换并结束在它所属的物理内存空间中。
x86当然有I/O空间,而且行为非常相似,除了内核中的低级,outb/outw/outl(以及它们的输入表兄弟)指令将用于从I/O空间写入/读取,与内存读/写指令。同样,用户空间应用程序应该通过 ioctls() 和映射的内存段进行通信,因为内核负责像这样的安全/访问内存。
对于您的第二个问题,有点类似于上述问题,但是适用于 Linux 的现代 PCIe 驱动程序将依赖 PCI 子系统来处理许多低级内部事务。您主要定义您负责的供应商/设备 ID,然后编写一个 .probe() 函数来获取您的 IRQ 并进行设备设置——您的记忆交给了您。
| 归档时间: |
|
| 查看次数: |
11304 次 |
| 最近记录: |