【问题标题】:What do file operations look like at assembly level汇编级别的文件操作是什么样的
【发布时间】:2019-09-06 02:49:01
【问题描述】:

在我看来,存储在辅助存储器(硬盘)中的所有内容都存储在文件中。因此,我将文件系统理解为关于文件的每个块的信息的系统化。(这反过来可能是关于 inode 信息的系统化)。

所以我想知道的是,当程序打算对文件进行操作时,在汇编和硬件级别会发生什么。我试着思考了一下,结果是这样的。

因此,如果我在第一段中写下的理解是正确的,那么任何需要一定字节数的读取操作,比如 X,都会将 X 除以块大小得到结果,比如 N,然后在文件系统中查询前 N 个块内容的位置,并获取存储在这些位置的内容。如果是硬盘,则从磁盘中获取内容。但是这种从磁盘读取是否涉及使用 DMA 并因此通过某些 DMA 控制器控制通信?

当读取所需的字节数时,它们是否将内容放入执行程序的堆栈中,其中一个变量将保存所需的字节数,或者因此获得的内容被放置在其他位置,例如堆?

对于写操作,我可以想到类似的机制,取偏移量,确定所需的块号,然后将要写入的新字节划分为块,并在文件系统中更新新块。

如果我以上理解有误,请指正。

但是,我想不出任何对关闭文件有重要意义的事情,也无法弄清楚不关闭文件在硬件和组装方面的不良影响。

我看过以下帖子:

http://www.brokenthorn.com/Resources/OSDev20.html

http://www.brokenthorn.com/Resources/OSDev20.html.

在这里,我可以在汇编中看到用于写入软盘设备或进行 DMA 的插图,但在以下章节中:

http://www.brokenthorn.com/Resources/OSDev22.html

这与文件系统有关,我无法准确找出文件操作的汇编级详细信息。 (虽然在前面的一些章节中,已经介绍了从 FAT 读取,但据我所知,它使用了 BIOS 中断)。

那么简而言之,在文件打开、文件读取、文件写入和文件关闭期间,硬件和程序集级别会发生什么?

【问题讨论】:

  • 您是否正在尝试编写设备驱动程序?
  • @SomeName : 目前没有,只是想了解在文件 I/O 期间在程序集级别会发生什么
  • 在文件打开过程中,系统使用给定的路径和文件名来定位和打开文件。在具有虚拟内存的典型系统上,对于使用 DMA 或总线主控的读/写操作,用户缓冲区被锁定并转换为一组物理页面,对于 X86 系统大小为 4KB,然后是一个“描述符”列表,其中包含创建物理地址和大小并用于读/写操作。在读或写之后,用户缓冲区被解锁。文件关闭将释放任何系统创建的缓冲区和任何与打开文件相关的分配内存。
  • 然后在文件系统中查询前 N 个块的内容的位置,并获取存储在这些位置的内容。不完全是。在普通的现代操作系统中,内核的文件读取实现将首先检查该文件数据的那部分是否缓存在 RAM(页面缓存)中不关心它来自磁盘的哪个位置。仅当未命中时,VFS / 页面缓存才必须找出如何将数据放入内存中,然后将其复制到用户空间。进行read 系统调用的进程不知道这些,它只是做了例如rax=0 / syscall (x86-64 Linux)
  • 在汇编级别发生的一切与在操作系统内核中实际实现文件访问的 C 代码中所表达的不同。有一小部分神奇的汇编代码实现了从进程代码到内核代码的转换,但除此之外,您无需考虑汇编级别发生的事情来了解它是如何工作的。

标签: file assembly filesystems


【解决方案1】:

文件操作在汇编级别是什么样子的

在应用程序中,这是使用系统调用完成的(例如,x86 CPU 上的 int 指令)。这样的系统调用会调用操作系统中的函数。

操作系统中的那个函数通常是一个用汇编语言编写的短函数,它调用另一个通常用“高级”编程语言(通常是 C;但当然也可以用汇编语言编写这个函数)编写的函数。

第二个函数会调用很多其他函数。

在硬盘或软盘上,数据以扇区的形式存储。每个扇区包含一定数量的字节(例如 512),您只能读取或写入完整的扇区,而不是单个字节。磁盘对文件一无所知。

在典型的操作系统中,文件处理涉及两种不同类型的功能:

1) 设备驱动功能

这些函数用于从磁盘读取或写入“扇区”数据。这取决于 CPU 和磁盘驱动器类型,这实际上是如何完成的。

在最简单的情况下,你有一个带有内存映射 I/O 的 CPU,你既不使用中断也不使用 DMA。历史悠久的 Commodore 1581 软盘驱动器就是一个例子。

在这种情况下,软件只需将字节写入地址即可将一些数据写入硬件 - 与将字节写入 RAM 的方式相同。从硬件中读取就像从 RAM 中读取一个字节一样。

软件会将一些数据写入硬件,指示磁盘驱动器从磁盘读取一些数据。然后软件不断地从某个地址读取数据。该数据包含磁盘驱动器是否准备就绪的信息。一旦磁盘驱动器准备好,软件就会通过从另一个地址读取数据来读取实际数据。写作也是如此。

如果您使用不使用内存映射 I/O 的 CPU,访问硬件不会像访问 RAM 那样工作,而是使用特殊指令(inout)。 (旧的 x86 计算机就是一个例子。)

如果使用中断(如在现代计算机中),软件不需要连续检查磁盘驱动器是否准备好。一旦磁盘驱动器报告准备就绪,CPU 就会调用一个特殊函数——所谓的“中断处理程序”。

如果使用 DMA(如在现代计算机中),磁盘驱动器可以直接将从磁盘读取的数据写入 RAM(或从 RAM 读取要写入的数据)。所以软件只需要写入指示磁盘驱动器写入某个扇区的特殊数据即可。软件不必写入应写入磁盘的实际数据,因为磁盘驱动器会直接从 RAM 中读取这些数据。 (阅读也是如此。)

2) 文件系统功能

这些函数将调用“设备驱动程序”函数来访问磁盘。

文件系统或多或少只是一些描述文件如何存储在磁盘上的描述。如果磁盘使用“FAT16”文件系统,则磁盘上有三个区域:FAT、根目录和簇。

(在使用“inode”的文件系统上,这有点不同;但是,原理是一样的。)

FAT 包含有关某些文件在磁盘上的存储位置以及哪些簇是空闲的信息。根目录包含有关磁盘上文件的名称(以及更多信息,例如文件大小)的信息。并且集群包含实际的文件数据。

当将文件写入磁盘时,文件系统函数将读取 FAT 的扇区(通过调用“设备驱动程序”的函数)。它将检查 FAT 的内容以查找空闲簇。现在它将读取根目录,添加写入文件的文件名并将根目录写回磁盘。然后函数会将文件的实际数据写入集群。最后,函数会更新FAT(相应扇区不再空闲)和根目录(文件大小不再为零)数据,并将这些信息写回磁盘。

【讨论】:

  • 没有内存映射 I/O 的 CPU。 x86 具有内存映射 I/O,它广泛存在于现代设备驱动程序中,AFAIK! in/out 很慢,尽可能避免使用。 (PCI / PCIe 确实有单独的 IO 与内存地址空间,但设备可以在内存空间中拥有部分/全部 MMIO 寄存器。)在现代 Linux 系统上,使用 lspci -v 查看每个设备的内存和 IO 范围.许多只有内存,通常只有 256 字节或 2k 或 4k 或其他东西(用于保存一些 MMIO 寄存器)。
  • @PeterCordes 谢谢。我将“没有内存映射 I/O”更改为“不仅有内存映射 I/O”。当然,任何 CPU(不仅具有片上内存)都可以进行内存映射 I/O。
  • 您仍然声称 x86 肯定使用 in/out 与硬件通信或设置 DMA。根据lspci -v 的说法,我的 NVMe SSD 没有任何 I/O 端口,只有 16k 内存映射 I/O 空间,因此它肯定会使用正常的加载/存储来编程 DMA 传输。我的e1000e NFS 以太网也是如此。根据lateblt.tripod.com/atapi.htm,ATA PIO 确实使用rep insw 之类的东西来传输扇区,所以你的描述在那里是准确的。但是en.wikipedia.org/wiki/Programmed_input/output 说 CPU 驱动的传输可以描述为内存或 IO 端口的 PIO。
  • x86 具有非内存映射 I/O,但出于性能原因,许多现代设备都避免使用它,即使使用 DMA 完成批量传输也是如此。
  • @MartinRosenau:你在这里提到的设备驱动程序,它到底是用于什么设备的?您能否简要介绍一下该设备驱动程序的电子操作?
猜你喜欢
  • 2012-03-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-04
  • 2017-01-04
  • 2014-06-20
  • 2011-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多