磁盘IO操作通常如何在内核级程序集中查看?

时间:2012-04-01 17:53:05

标签: assembly kernel hardware arm

在userland中,执行磁盘IO就像链接C库一样简单,或者,如果您喜欢冒险,则直接执行系统调用。我想知道内核本身是如何执行IO的。

换句话说,假设我假设在特权模式下在裸机上运行应用程序。我如何访问通过SATA连接连接的磁盘硬件?我是否从预先确定的地址执行加载?是否有某种与io相关的指令?

2 个答案:

答案 0 :(得分:4)

Linux有一个函数调用跟踪器。我建议您跟踪IO请求。

警告:以下是我写的,实际上并不知道真实的细节。

基本上,您需要使用PCI API与磁盘设备通信以设置直接内存访问,因为您不希望一次读取一个字节的磁盘块(或以太网帧)。因此,您告诉硬件某些存储区(从地址X开始,长度为N字节)是DMA区域。您还设置了内存缓存,以便知道RAM区域中的数据可以在没有CPU写入的情况下进行更改,因此即使您是单处理器,它也是不稳定的。

假设硬件一次只支持一个DMA事务。然后发送诸如“读取512字节扇区号X(即磁盘的字节X <&lt; 9到((X + 1)&lt;&lt; 9)-1”之类的命令并将其放入DMA区域。你做完了,发动中断“。磁盘控制器做它的东西(它有一个ARM CPU和所有东西),通过PCI与北桥集线器通过它,并通过它与RAM,绕过CPU。写入完成(或错误输出)时,将触发中断。当发生这种情况时,你等待(好吧,内核在你的进程休眠时运行其他进程)。数百万个CPU周期之后(10ms是2Ghz芯片的永恒),一个中断点火。通知操作系统已完成读取操作。操作系统可以在RAM中查看数据。然后它将其复制到用户进程内存中,或者它位于共享页面中,用户进程可以从那里读取它。用户进程恢复(好吧,放在准备好运行的队列中,最终在调度程序感觉就好的情况下运行)。

通过将数据复制到DMA空间并发送“将数据从DMA区域写入磁盘上的扇区号X并在完成时触发中断”命令来进行写入工作。然后磁盘可能在写入完成后或从RAM读取数据后立即触发中断,在这种情况下,fsync不能正常工作,并且数据库和文件系统因电源故障而损坏。

OS块缓存适用于整个4KB ram页面,因此它一次读取8个扇区,但想法是一样的。新磁盘有一个与4KB sectors一起使用的本机API,但这个想法是一样的。 USB与PCI不同,但想法是一样的。各种高性能硬件都有聪明的API,可以加速所有这些,同时在飞行中进行多项交易,并对其订购进行各种控制。

卸载TCP / IP的网络接口可能有一个围绕数据包而不是以太网帧的API,因为NIC了解TCP / IP标头。

实际上是网络设备的块设备会隐藏某处的转换(部分在硬件中,部分在固件中,部分在软件中)。

在Linux中,对于我的硬件,我认为它是这样的:

当模块sata_piix is loaded时,它告诉操作系统它支持的设备的PCI设备ID和操作系统应该使用的回调,结构中的所有described。通用OS PCI拓扑代码发现ID为8086:27c0的设备ICH7,并在driver's table中找到它,因此操作系统决定这是此硬件的正确驱动程序。在该表中,驱动程序会发现它应该将此设备视为an ICH6 SATA device,稍后。由于驱动程序表示它支持该设备,因此操作系统registers具有驱动程序的设备。

从那里分配设备的控制区域并prepared。 DMA is set upPCI Bus Mastering is enabled(这允许控制器自己启动PCI数据传输到RAM(当数据就绪时),而不是等待CPU启动传输)。中断处理程序are set up

代码是通用的,按时间顺序支持许多代硬件:

  1. PIO
  2. Single/Multi-word DMA
  3. UDMA
  4. SATA
  5. AHCI
  6. 因此很难阅读。跟踪会让事情变得更容易。

答案 1 :(得分:1)

这取决于很多事情。我不太了解ARM,但我想会有某种outportb指令允许你通过总线发送数据。与I / O设备通信是特定于供应商的,但通常内核可能存储器映射(在GPU帧缓冲器的情况下)设备的寄存器或简单地通过I / O设备可识别的总线发送请求(通常是设备特定的) 。请求通常只是序列化的结构信息,包含起始扇区,长度和地址,告诉总线I / O转移到哪里。

如果您想在内核中执行此类操作(例如Linux),则已有用于创建I / O结构并将其提交到特定设备的功能,因此您无需自己执行此操作。如果您正在编写自己的操作系统,我建议您查看Linux源代码,其中包含如何在许多架构的汇编级别执行此操作的示例。