0

试图了解现代消费者台式计算机上的数据流。

  1. 首先看一个 SATA 端口。如果您想将一些字节加载到 RAM 中,CPU 是否将该请求发送到处理对 SATA 设备的请求的内存控制器,并且该数据是否由内存控制器移动到 RAM 中,或者 CPU 缓存或寄存器是否参与数据?

  2. 我假设操作系统通常会阻塞线程,直到 I/O 请求完成。内存控制器是否发送中断以让操作系统知道它可以再次将该线程调度到队列中?

  3. 以太网:那么假设上述步骤已经完成,其中文件的某些字节已加载到 RAM 上,内存是否会被内存控制器移动到以太网控制器,或者 CPU 是否参与保存这些数据?

  4. 如果您使用带有 localhost 的套接字怎么办?我们是只对内存控制器进行一轮研究,还是完全涉及以太网控制器?

  5. SATA 到 SATA 存储传输在任何地方缓冲?

我知道这是很多问题,如果您可以发表评论,我将不胜感激!我真的很想了解这里的基本原理。如果没有这些细节,我很难进入更高层次的抽象......

4

2 回答 2

2

内存控制器本身不会创建请求(它没有 DMA 或总线主控功能)。

内存控制器主要用于将请求路由到正确的位置。例如,如果 CPU(或设备)要求从物理地址 0x12345678 读取 4 个字节,则内存控制器使用物理地址来确定是否将该请求路由到 PCI 总线,或不同的 NUMA 节点/不同的内存控制器(例如,使用快速路径或超传输或全路径链接到其他芯片/内存控制器),或其本地连接的 RAM 芯片。如果内存控制器将请求转发到其本地连接的 RAM 芯片;然后内存控制器还处理“哪个内存通道”和时序部分;并且还可以处理加密和 ECC(检查/纠正错误,并将它们报告给操作系统)。

大多数设备都支持自己的总线主控。

因为大多数操作系统使用分页“在虚拟内存中连续”通常并不意味着“在物理内存中连续”。因为设备只处理物理地址,而大多数传输在物理内存中并不连续;大多数设备支持使用“范围列表”。例如,如果磁盘控制器驱动程序想要从磁盘读取 8 KiB,那么驱动程序可能会告诉磁盘控制器“从物理地址 0x11111800 获取前 2 KiB,然后从物理地址 0x22222000 获取下一个 4 KiB,然后从物理地址 0x22222000 获取最后 2 KiB 来自物理地址 0x33333000"; 并且磁盘控制器将按照此列表将 8 KiB 传输的部分传输到所需的地址。

因为设备使用物理地址并且几乎所有软件(包括内核、驱动程序)通常主要使用虚拟地址,某些东西(内核)必须将虚拟地址(例如从“read()”函数调用)转换为“范围列表" 设备驱动程序(可能)需要。当使用 IOMMU(用于安全或虚拟化)时,此转换可能包括配置 IOMMU 以适应传输;在这种情况下,最好将它们视为 IOMMU 可以转换/转换为物理地址的“设备地址”(其中设备使用“设备地址”而不是实际物理地址)。

对于一些(比较少见,主要是高端服务器)案例;主板/芯片组还可能包含某种 DMA 引擎(例如“英特尔 QuickData 技术”)。取决于 DMA 引擎;这可能能够将数据直接注入 CPU 缓存(而不是像大多数设备那样只能从 RAM 传输数据),并且可能能够处理直接“从一个设备到另一个设备”的传输(而不是必须使用RAM 作为缓冲区)。然而; 一般来说(因为设备驱动程序需要在没有“相对稀有”的 DMA 引擎时工作)很可能主板/芯片组提供的任何 DMA 引擎都不会被操作系统或驱动程序很好地支持(并且很可能 DMA 引擎赢了'根本不支持或使用)。

于 2021-10-09T02:10:50.263 回答
1

首先看一个 SATA 端口。如果您想将一些字节加载到 RAM 中,CPU 是否将该请求发送到处理对 SATA 设备的请求的内存控制器,并且该数据是否由内存控制器移动到 RAM 中,或者 CPU 缓存或寄存器是否涉及数据?

运行过程中不涉及 CPU。它是一个 AHCI 进行传输,它是一个 PCI DMA 设备。

Intel 的 AHCI ( https://www.intel.ca/content/www/ca/en/io/serial-ata/serial-ata-ahci-spec-rev1-3-1.html ) 用于 SATA 磁盘. 同时,对于更现代的 NVME 磁盘,使用 NVME PCI 控制器 ( https://wiki.osdev.org/NVMe )。

操作系统基本上会在 RAM 中写入以写入 AHCI 的寄存器。这样,它将能够告诉 AHCI 做一些事情并告诉它在特定位置写入 RAM(可能在请求磁盘上数据的用户模式进程提供/分配的缓冲区中)。该操作是 DMA,因此 CPU 并没有真正参与。

fstream在 C++ 中,您可能使用或直接在操作系统提供的库中对操作系统进行 API 调用来请求数据。例如,在 Windows 上,您可以使用WriteFile()函数 ( https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile ) 写入某些文件。

在下面,该库是一个进行系统调用的瘦包装器(标准 C++ 库也是如此)。您可以在调用克隆系统调用时谁设置 RIP 寄存器中浏览我的答案?有关系统调用以及它们如何在现代系统上工作的更多信息。

内存控制器并没有真正参与。它涉及写入 AHCI 的寄存器,但 Brendan 的回答可能对这件事更有用,因为我不太清楚。

我假设操作系统通常会阻塞线程,直到 I/O 请求完成。内存控制器是否发送中断以让操作系统知道它可以再次将该线程调度到队列中?

是的,操作系统会阻塞线程,是的,AHCI 在命令完成时会触发 MSI 中断。

操作系统会将进程放入等待 IO 的进程队列中。AHCI 确实使用 PCI 设备的 MSI 功能触发中断。MSI 功能是一种特殊功能,它允许绕过现代 x86 处理器的 IO APIC,并直接向本地 APIC 发送处理器间中断。本地 APIC 然后在 IDT 中查找,就像您期望的那样触发向量并使处理器跳转到关联的处理程序。

它是用于区分触发中断的设备的处理程序编号,这使得操作系统可以轻松地将设备的正确处理程序放置在该中断编号(驱动程序)上。

操作系统有一个驱动程序模型,它考虑到将在现代计算机上使用的不同类型的设备。驱动程序模型通常采用虚拟文件系统的形式。虚拟文件系统基本上将每个设备作为文件呈现给操作系统的上层。上层基本上对文件进行 open、read、write 和 ioctl 调用。下面,驱动程序将执行复杂的操作,例如通过写入 AHCI 的寄存器来触发读/写周期,并将进程放在其他队列中等待 IO。

从用户模式(如调用 fstream 的 open 方法时),它实际上是一个系统调用。系统调用处理程序将检查所有权限并确保请求一切正常,然后再返回文件句柄。

以太网:那么假设上述步骤已经完成,其中文件的某些字节已加载到 RAM 上,内存是否会被内存控制器移动到以太网控制器,或者 CPU 是否参与保存这些数据?

以太网控制器也是 PCI DMA 设备。它直接在 RAM 中读写。

以太网控制器是一个 PCI DMA 设备。我从未编写过以太网驱动程序,但我可以说它只是直接在 RAM 中读写。现在对于网络通信,您将拥有与文件类似但不属于虚拟文件系统的套接字。网卡(包括以太网控制器)不作为文件呈现给上层。相反,您使用套接字与控制器进行通信。套接字未在 C++ 标准库中实现,但作为操作系统提供的库存在于所有广泛的平台上,必须从 C++ 或 C 中使用。套接字本身也是系统调用。

如果您使用带有 localhost 的套接字怎么办?我们是只对内存控制器进行一轮研究,还是完全涉及以太网控制器?

以太网控制器可能不涉及。

如果您使用带有 localhost 的套接字,操作系统只会将数据发送到环回接口。维基百科的文章在这里非常直接(https://en.wikipedia.org/wiki/Localhost):

在计算机网络中,localhost 是一个主机名,指的是用于访问它的当前计算机。它用于通过环回网络接口访问在主机上运行的网络服务。使用环回接口绕过任何本地网络接口硬件。

SATA 到 SATA 存储传输在任何地方缓冲?

它从第一个设备传输到 RAM,然后再传输到第二个设备。

在我之前为 AHCI 提供的链接中,声明如下:

该规范定义了高级主机控制器接口 (ACHI) 的功能行为和软件接口,这是一种允许软件与串行 ATA 设备通信的硬件机制。AHCI 是一种 PCI 类设备,充当系统内存和串行 ATA 设备之间的数据移动引擎。

AHCI 不适用于从 SATA 迁移到 SATA。它用于从 SATA 移动到 RAM 或从 RAM 移动到 SATA。因此,SATA 到 SATA 操作涉及将数据带入 RAM,然后将数据从 RAM 移动到其他 SATA 设备。

于 2021-10-08T21:53:47.407 回答