gpt4 book ai didi

linux - 从 CPU 向 PCIe 地址空间写入一个字节的精确细节

转载 作者:太空宇宙 更新时间:2023-11-04 09:58:10 28 4
gpt4 key购买 nike

我对让 CPU 将值写入 PCIe 卡的内存所涉及的确切 系列步骤感到非常困惑。很难理解您在 Internet 上阅读的内容的精确含义,因此我希望有人能阅读我对正在发生的事情的理论并指出任何错误。

设置

假设我有一个带有一些内存的 PCIe 卡。为了便于讨论,假设以下具体设置:

  • 它有 4 MB 可通过基地址寄存器 0 访问(无论那是什么意思)
  • 它是整个系统中唯一的PCIe卡
  • 它插入一个 PCIe 插槽,该插槽通过主板中的铜线连接到根复合体
  • 有一个根联合体直接连接到 CPU 的总线(这是正常的连接方式吗?)
  • PCIe 卡以某种方式配置为设备编号 0(这是如何完成的?)
  • 我们使用的是 Linux。

让我们再谈谈术语:

  • 系统总线 是 CPU 自己的总线。
  • PCIe 总线指的是主板上 CPU 和 PCIe 插槽之间的电线
  • 一个驱动是一个Linux内核模块
  • 设备是一个字面上的物理对象
  • 一个device struct是由内核填充的pci_dev结构
  • BAR(基地址寄存器)是 PCIe 设备配置空间中的字段
  • BAR 空间 是由 BAR 中的值指示 (?) 的地址空间。

我对正在发生的事情的理论

  1. 在启动时,Linux 开始探测不同的地址以查看那里是否有任何内容。

    • 由于 PCIe 总线线仅通过桥接器连接到系统总线线(即系统总线上的 PCIe Controller ),Linux 必须知道如何与 PCIe Controller 交互。
    • Linux 向 PCIe Controller 发送特殊命令(通过内存映射 IO?),最终在 PCIe 线上触发正确的一系列电压
    • 如果得到响应,它将在配置空间中填充一个pci_dev结构
    • 在未来的某个时候(什么时候?)内核将遍历 PCI 驱动程序列表以尝试将它们与设备匹配
  2. 当 Linux 检测到一个设备时,它会将其 BAR 空间映射到系统总线。 (这是怎么做到的?)假设它将 BAR0 空间映射到系统总线上的地址 0x555000000x5550FFFF
    • Linux 必须告诉根复合体听取这些地址,并且它们对应于它检测到的 PCIe 卡。
    • 顺便说一下,Linux 会将我们 PCIe 卡上的基地址寄存器 0 设置为在其基地址字段中包含 0x55500000(为什么要麻烦?)
  3. 0x555000000x5550FFFF 之间的系统总线上的后续写入被根复合体“捕获”,并发布到 PCIe 卡
    • 根复合体基本上会构建一个包含所有 header 和校验和等的数据包,并通过主板的铜线将它们发送到 PCIe 插槽
  4. 假设 CPU 将 0xDEADBEEF 写入系统总线上的地址 0x55501230,并且根复合体将数据包发送到 PCIe 卡,卡接收数据包并将 0xDEADBEEF 写入其本地 4 MB 内存中的 0x01230

那么:这其中哪些部分是正确的,哪些部分是错误的?

最佳答案

我的经验是使用英特尔处理器,因此下面的一些细节可能特定于英特尔处理器,但大部分都是通用的。此外,我不知道 Linux 如何识别要为每个设备加载的驱动程序的详细信息,所以我跳过了这个问题。

现代 CPU 没有系统总线(除非隐藏在 CPU 本身内)。它们具有内存 channel 、PCIe 根端口和连接到芯片组的 DMI 端口(也称为外围 Controller 集线器或 PCH)。 PCH 包含额外的设备并且可能有额外的根端口。根复合体包括集成到 CPU 和 PCH 中的电路。 (一些 CPU SoC 没有 DMI 或 PCH,所有根复合体电路都在 CPU SoC 中。)

即使您的卡是整个系统中唯一的 PCIe 卡,也有其他 PCIe 设备集成到根复合体中(称为 RCIEP 或根复合体集成端点)。这些可能在 CPU 中或在 PCH 中。

连接到 PCIe 根端口的设备将被配置为某个非零总线编号上的设备 0。总线编号取决于设备连接到的 PCIe 根端口(即插槽)以及 BIOS 配置 PCIe 总线的方式。 (同一个插槽通常会有相同的总线号,但也可能不同,这取决于连接到其他 PCIe 根端口的是什么。)

您的其他假设和术语都很好。

软件通过对 I/O 端口 0xcf8 和 0xcfc 使用输入/输出指令,或使用内存映射配置空间来访问 PCI 配置空间。 PCI配置空间的内存地址范围由BIOS设置。软件通过查看 ACPI 表找出地址。将这些 I/O 或内存访问转换为 PCIe 信号的机制完全在根复合体硬件中。

PCI 配置空间地址范围内的偏移量控制正在访问的设备/寄存器软件。例如,访问 MMCFG + 0 会访问设备 0:0.0 的寄存器偏移量 0。访问 MMCFG + 0x1000 访问设备 0:0.1 的寄存器偏移量 0,访问 MMCFG + 0x102000 访问设备 1:0.2 的寄存器偏移量 0。

软件读取每个设备地址偏移量 3:0 处的供应商 ID/设备 ID 寄存器,以检测该设备地址是否存在设备。如果没有设备存在,PCI Controller 返回 0xffffffff。如果存在设备,则该设备返回供应商 ID 和设备 ID,从而允许软件确定设备的类型。

每个设备都有 6 个 BAR 寄存器,偏移量为 0x10、0x14、... 0x24。如果设备支持 64 位 BAR,则两个相邻的 BAR 寄存器用于配置单个区域。通常,BIOS 会配置每个设备的 BAR,还会配置根复合体中的其他(隐藏)寄存器,以使其能够将内存访问路由到正确的设备。软件通常只写入 BAR 寄存器以检测区域大小,然后恢复由 BIOS 设置的值。根据根联合体硬件,软件可能会或可能不会更改 BAR 值,并且仍然可以正常访问。

关于linux - 从 CPU 向 PCIe 地址空间写入一个字节的精确细节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58443506/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com