2012-04-01 58 views
4

在用户空间中,执行磁盘IO与链接C库一样容易,或者如果您喜欢冒险,可以直接执行系统调用。我想知道内核本身如何执行IO。磁盘IO操作如何通常在内核级程序集中查找?

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

回答

4

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

警告:以下是我自己写的,没有真正知道真实的细节。

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

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

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

OS块缓存适用于整个4KB RAM的页面,所以每次读取8个扇区,但这个想法是一样的。新磁盘有一个本地API,与4KB sectors一起使用,但这个想法是一样的。 USB与PCI不同,但这个想法是相同的。各种高性能硬件都具有巧妙的API,可以加快这些速度,同时有多个事务处理以及对它们的排序进行各种控制。

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

确实是网络设备的块设备隐藏翻译的某处(硬件部分,固件部分,软件部分)。

在Linux中,我的硬件,我觉得是这样的:

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

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

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

  1. PIO
  2. Single/Multi-word DMA
  3. UDMA
  4. SATA
  5. AHCI

所以很难阅读。跟踪会使它更容易。

1

这取决于很多东西。我对ARM的了解不多,但我会想象有一些outportb指令可以让你通过总线发送数据。与I/O设备通信是供应商特定的,但通常内核可能会对设备的寄存器进行映射(在GPU帧缓冲区的情况下),或者只是通过I/O设备可以识别的总线发送请求(通常是设备特定的) 。并且请求通常只是包含起始扇区,长度和告诉总线I/O转移到的地址的序列化结构信息。

如果你想在内核(Linux的例子)已经有创建的I/O结构,并提交到特定的设备,所以你不需要做自己的功能做这种事情。如果你正在编写你自己的操作系统,我会建议看一看Linux源代码,其中有许多体系结构的汇编级别的例子。