理解xv6——3.9 磁盘驱动程序
资讯
2024-02-17
447
The IDE device provides access to disks connected to the PC standard IDE controller. IDE is now falling out of fashion in favor of SCSI and SATA, but the interface is simple and lets us concentrate on the overall structure of a driver instead of the details of a particular piece of hardware.
IDE设备提供对连接到PC标准IDE控制器的磁盘的访问。IDE现在已经不流行了,取而代之的是SCSI和SATA,但是它的接口很简单,可以让我们专注于驱动程序的整体结构,而不是某个特定硬件的细节。
Xv6 represent file system blocks using struct buf (3850) . BSIZE (4055) is identical to the IDEs sector size and thus each buffer represents the contents of one sector on a particular disk device. The dev and sector fields give the device and sector number and the data field is an in-memory copy of the disk sector. Although the xv6 file system chooses BSIZE to be identical to the IDEs sector size, the driver can handle a BSIZE that is a multiple of the sector size. Operating systems often use bigger blocks than 512 bytes to obtain higher disk throughput.
Xv6使用struct buf(3850)表示文件系统块。BSIZE(4055)与IDE的扇区大小相同,因此每个缓冲区表示特定磁盘设备上一个扇区的内容。dev和sector字段给予设备和扇区号,data字段是磁盘扇区的内存副本。尽管xv6文件系统选择的BSIZE与IDE的扇区大小相同,但驱动程序可以处理扇区大小倍数的BSIZE。操作系统通常使用大于512字节的块来获得更高的磁盘吞吐量。
The flags track the relationship between memory and disk: the B_VALID flag means that data has been read in, and the B_DIRTY flag means that data needs to be written out.
标志跟踪内存和磁盘之间的关系:B_VALID标志意味着数据已经被读入,而B_DIRTY标志意味着数据需要被写出。
The kernel initializes the disk driver at boot time by calling ideinit (4251) from main (1232) . Ideinit calls ioapicenable to enable the IDE_IRQ interrupt (4256) . The call to ioapicenable enables the interrupt only on the last CPU (ncpu-1): on a two processor system, CPU 1 handles disk interrupts.
内核在boot时通过从main(1232)调用ideinit(4251)来初始化磁盘驱动程序。Ideinit调用ioapicenable来启用IDE_IRQ中断(4256)。对ioapicenable的调用仅在最后一个CPU(ncpu-1)上启用中断:在双处理器系统中,CPU 1处理磁盘中断。
Next, ideinit probes the disk hardware. It begins by calling idewait (4257) to wait for the disk to be able to accept commands. A PC motherboard presents the status bits of the disk hardware on I/O port 0x1f7. Idewait (4238) polls the status bits until the busy bit (IDE_BSY) is clear and the ready bit (IDE_DRDY) is set.
接下来,ideinit探测磁盘硬件。它首先调用idewait(4257)来等待磁盘能够接受命令。PC主板在I/O端口0x1f7上显示磁盘硬件的状态位。Idewait(4238)轮询状态位,直到忙碌位(IDE_BSY)被清除并且就绪位(IDE_DRDY)被设置。
Now that the disk controller is ready, ideinit can check how many disks are present. It assumes that disk 0 is present, because the boot loader and the kernel were both loaded from disk 0, but it must check for disk 1. It writes to I/O port 0x1f6 to select disk 1 and then waits a while for the status bit to show that the disk is ready (4259-4266) . If not, ideinit assumes the disk is absent.
现在磁盘控制器已经准备好了,ideinit可以检查有多少个磁盘。它假定磁盘0存在,因为boot加载程序和内核都是从磁盘0加载的,但它必须检查磁盘1。它写入I/O端口0x1f6以选择磁盘1,然后等待一段时间,等待状态位显示磁盘已就绪(4259-4266)。如果没有,ideinit假设磁盘不存在。
After ideinit, the disk is not used again until the buffer cache calls iderw, which updates a locked buffer as indicated by the flags. If B_DIRTY is set, iderw writes the buffer to the disk; if B_VALID is not set, iderw reads the buffer from the disk.
在ideinit之后,直到缓冲区缓存调用iderw(这将更新由标志指示的锁定缓冲区),磁盘才会再次使用。如果设置了B_DIRTY,则iderw将缓冲区写入磁盘;如果未设置B_VALID,则iderw从磁盘读取缓冲区。
Disk accesses typically take milliseconds, a long time for a processor. The boot loader issues disk read commands and reads the status bits repeatedly until the data is ready (see Appendix B). This polling or busy waiting is fine in a boot loader, which has nothing better to do.
In an operating system, however, it is more efficient to let another process run on the CPU and arrange to receive an interrupt when the disk operation has completed. Iderw takes this latter approach, keeping the list of pending disk requests in a queue and using interrupts to find out when each request has finished. Although iderw maintains a queue of requests, the simple IDE disk controller can only handle one operation at a time. The disk driver maintains the invariant that it has sent the buffer at the front of the queue to the disk hardware; the others are simply waiting their turn.
磁盘访问通常需要几毫秒,这对于处理器来说是很长的时间。boot加载程序发出磁盘读取命令并重复读取状态位,直到数据就绪(参见附录B)。这种轮询或忙碌等待在boo加载程序中很好,它没有更好的事情可做。
然而,在操作系统中,让另一个进程在CPU上运行并安排在磁盘操作完成时接收中断会更有效。Iderw采用后一种方法,将挂起的磁盘请求列表保存在队列中,并使用中断来查找每个请求何时完成。虽然iderw维护了一个请求队列,但简单的IDE磁盘控制器一次只能处理一个操作。磁盘驱动程序保持不变式,即它已将队列前面的缓冲区发送到磁盘硬件;其他人只是在等着轮到他们。
Iderw (4354) adds the buffer b to the end of the queue (4367-4371) . If the buffer is at the front of the queue, iderw must send it to the disk hardware by calling idestart (4326-4328) ; otherwise the buffer will be started once the buffers ahead of it are taken care of.
Iderw(4354)将缓冲器b添加到队列(4367-4371)的末尾。如果缓冲区位于队列的前面,则iderw必须通过调用idestart(4326-4328)将其发送到磁盘硬件;不然就得等它前面的缓冲器被处理完,此缓冲器才会启动。
Idestart (4274) issues either a read or a write for the buffers device and sector, according to the flags. If the operation is a write, idestart must supply the data now (4296) . idestart moves the data to a buffer in the disk controller using the outsl instruction; using CPU instructions to move data to/from device hardware is called programmed I/O. Eventually the disk hardware will raise an interrupt to signal that the data has been written to disk.
If the operation is a read, the interrupt will signal that the data is ready, and the handler will read it. Note that idestart has detailed knowledge about the IDE device, and writes the right values at the right ports. If any of these outb statements is wrong, the IDE will do something differently than what we want. Getting these details right is one reason why writing device drivers is challenging.
Idestart(4274)根据标志对缓冲器的设备和扇区发出读或写。如果操作是写,则idestart必须现在提供数据(4296)。idestart使用outs 1指令将数据移动到盘控制器中的缓冲器;使用CPU指令向设备硬件移动数据或从设备硬件移动数据被称为编程I/O。最后,磁盘硬件将引发一个中断,表示数据已写入磁盘。
如果操作是读操作,中断将发出数据就绪的信号,处理程序将读取数据。请注意,idestart具有有关IDE设备的详细信息,并在正确的端口写入正确的值。如果这些outb语句中的任何一个是错误的,IDE将执行与我们所希望的不同的操作。编写设备驱动程序之所以具有挑战性,其中一个原因就是要正确处理这些细节。
Having added the request to the queue and started it if necessary, iderw must wait for the result. As discussed above, polling does not make efficient use of the CPU. Instead, iderw yields the CPU for other processes by sleeping, waiting for the interrupt handler to record in the buffers flags that the operation is done (4378-4379) . While this process is sleeping, xv6 will schedule other processes to keep the CPU busy.
将请求添加到队列并在必要时启动它之后,iderw必须等待结果。如上所述,轮询不能有效地利用CPU。相反,iderw通过休眠将CPU留给其他进程,等待中断处理程序在缓冲区的标志中记录操作已完成(4378-4379)。当这个进程处于休眠状态时,xv6会调度其他进程,让CPU保持忙碌。
Eventually, the disk will finish its operation and trigger an interrupt. trap will call ideintr to handle it (3424) . Ideintr (4304) consults the first buffer in the queue to find out which operation was happening. If the buffer was being read and the disk controller has data waiting, ideintr reads the data from a buffer in the disk controller into memory with insl (4317-4319) . Now the buffer is ready: ideintr sets B_VALID, clears B_DIRTY, and wakes up any process sleeping on the buffer (4321-4324) . Finally, ideintr must pass the next waiting buffer to the disk (4326-4328) .
最终,磁盘将完成其操作并触发中断。trap将调用ideintr来处理它(3424)。Ideintr(4304)查询队列中的第一个缓冲区以找出正在发生的操作。如果正在读取缓冲区并且磁盘控制器有数据等待,则ideintr使用insl(4317-4319)将数据从磁盘控制器中的缓冲区读取到内存中。现在缓冲区已经准备好了:ideintr设置B_VALID,清除B_DIRTY,并唤醒缓冲区中休眠的任何进程(4321-4324)。最后,ideintr必须将下一个等待缓冲区传递给磁盘(4326-4328)。
本站涵盖的内容、图片、视频等数据系网络收集,部分未能与原作者取得联系。若涉及版权问题,请联系我们删除!联系邮箱:ynstorm@foxmail.com 谢谢支持!
The IDE device provides access to disks connected to the PC standard IDE controller. IDE is now falling out of fashion in favor of SCSI and SATA, but the interface is simple and lets us concentrate on the overall structure of a driver instead of the details of a particular piece of hardware.
IDE设备提供对连接到PC标准IDE控制器的磁盘的访问。IDE现在已经不流行了,取而代之的是SCSI和SATA,但是它的接口很简单,可以让我们专注于驱动程序的整体结构,而不是某个特定硬件的细节。
Xv6 represent file system blocks using struct buf (3850) . BSIZE (4055) is identical to the IDEs sector size and thus each buffer represents the contents of one sector on a particular disk device. The dev and sector fields give the device and sector number and the data field is an in-memory copy of the disk sector. Although the xv6 file system chooses BSIZE to be identical to the IDEs sector size, the driver can handle a BSIZE that is a multiple of the sector size. Operating systems often use bigger blocks than 512 bytes to obtain higher disk throughput.
Xv6使用struct buf(3850)表示文件系统块。BSIZE(4055)与IDE的扇区大小相同,因此每个缓冲区表示特定磁盘设备上一个扇区的内容。dev和sector字段给予设备和扇区号,data字段是磁盘扇区的内存副本。尽管xv6文件系统选择的BSIZE与IDE的扇区大小相同,但驱动程序可以处理扇区大小倍数的BSIZE。操作系统通常使用大于512字节的块来获得更高的磁盘吞吐量。
The flags track the relationship between memory and disk: the B_VALID flag means that data has been read in, and the B_DIRTY flag means that data needs to be written out.
标志跟踪内存和磁盘之间的关系:B_VALID标志意味着数据已经被读入,而B_DIRTY标志意味着数据需要被写出。
The kernel initializes the disk driver at boot time by calling ideinit (4251) from main (1232) . Ideinit calls ioapicenable to enable the IDE_IRQ interrupt (4256) . The call to ioapicenable enables the interrupt only on the last CPU (ncpu-1): on a two processor system, CPU 1 handles disk interrupts.
内核在boot时通过从main(1232)调用ideinit(4251)来初始化磁盘驱动程序。Ideinit调用ioapicenable来启用IDE_IRQ中断(4256)。对ioapicenable的调用仅在最后一个CPU(ncpu-1)上启用中断:在双处理器系统中,CPU 1处理磁盘中断。
Next, ideinit probes the disk hardware. It begins by calling idewait (4257) to wait for the disk to be able to accept commands. A PC motherboard presents the status bits of the disk hardware on I/O port 0x1f7. Idewait (4238) polls the status bits until the busy bit (IDE_BSY) is clear and the ready bit (IDE_DRDY) is set.
接下来,ideinit探测磁盘硬件。它首先调用idewait(4257)来等待磁盘能够接受命令。PC主板在I/O端口0x1f7上显示磁盘硬件的状态位。Idewait(4238)轮询状态位,直到忙碌位(IDE_BSY)被清除并且就绪位(IDE_DRDY)被设置。
Now that the disk controller is ready, ideinit can check how many disks are present. It assumes that disk 0 is present, because the boot loader and the kernel were both loaded from disk 0, but it must check for disk 1. It writes to I/O port 0x1f6 to select disk 1 and then waits a while for the status bit to show that the disk is ready (4259-4266) . If not, ideinit assumes the disk is absent.
现在磁盘控制器已经准备好了,ideinit可以检查有多少个磁盘。它假定磁盘0存在,因为boot加载程序和内核都是从磁盘0加载的,但它必须检查磁盘1。它写入I/O端口0x1f6以选择磁盘1,然后等待一段时间,等待状态位显示磁盘已就绪(4259-4266)。如果没有,ideinit假设磁盘不存在。
After ideinit, the disk is not used again until the buffer cache calls iderw, which updates a locked buffer as indicated by the flags. If B_DIRTY is set, iderw writes the buffer to the disk; if B_VALID is not set, iderw reads the buffer from the disk.
在ideinit之后,直到缓冲区缓存调用iderw(这将更新由标志指示的锁定缓冲区),磁盘才会再次使用。如果设置了B_DIRTY,则iderw将缓冲区写入磁盘;如果未设置B_VALID,则iderw从磁盘读取缓冲区。
Disk accesses typically take milliseconds, a long time for a processor. The boot loader issues disk read commands and reads the status bits repeatedly until the data is ready (see Appendix B). This polling or busy waiting is fine in a boot loader, which has nothing better to do.
In an operating system, however, it is more efficient to let another process run on the CPU and arrange to receive an interrupt when the disk operation has completed. Iderw takes this latter approach, keeping the list of pending disk requests in a queue and using interrupts to find out when each request has finished. Although iderw maintains a queue of requests, the simple IDE disk controller can only handle one operation at a time. The disk driver maintains the invariant that it has sent the buffer at the front of the queue to the disk hardware; the others are simply waiting their turn.
磁盘访问通常需要几毫秒,这对于处理器来说是很长的时间。boot加载程序发出磁盘读取命令并重复读取状态位,直到数据就绪(参见附录B)。这种轮询或忙碌等待在boo加载程序中很好,它没有更好的事情可做。
然而,在操作系统中,让另一个进程在CPU上运行并安排在磁盘操作完成时接收中断会更有效。Iderw采用后一种方法,将挂起的磁盘请求列表保存在队列中,并使用中断来查找每个请求何时完成。虽然iderw维护了一个请求队列,但简单的IDE磁盘控制器一次只能处理一个操作。磁盘驱动程序保持不变式,即它已将队列前面的缓冲区发送到磁盘硬件;其他人只是在等着轮到他们。
Iderw (4354) adds the buffer b to the end of the queue (4367-4371) . If the buffer is at the front of the queue, iderw must send it to the disk hardware by calling idestart (4326-4328) ; otherwise the buffer will be started once the buffers ahead of it are taken care of.
Iderw(4354)将缓冲器b添加到队列(4367-4371)的末尾。如果缓冲区位于队列的前面,则iderw必须通过调用idestart(4326-4328)将其发送到磁盘硬件;不然就得等它前面的缓冲器被处理完,此缓冲器才会启动。
Idestart (4274) issues either a read or a write for the buffers device and sector, according to the flags. If the operation is a write, idestart must supply the data now (4296) . idestart moves the data to a buffer in the disk controller using the outsl instruction; using CPU instructions to move data to/from device hardware is called programmed I/O. Eventually the disk hardware will raise an interrupt to signal that the data has been written to disk.
If the operation is a read, the interrupt will signal that the data is ready, and the handler will read it. Note that idestart has detailed knowledge about the IDE device, and writes the right values at the right ports. If any of these outb statements is wrong, the IDE will do something differently than what we want. Getting these details right is one reason why writing device drivers is challenging.
Idestart(4274)根据标志对缓冲器的设备和扇区发出读或写。如果操作是写,则idestart必须现在提供数据(4296)。idestart使用outs 1指令将数据移动到盘控制器中的缓冲器;使用CPU指令向设备硬件移动数据或从设备硬件移动数据被称为编程I/O。最后,磁盘硬件将引发一个中断,表示数据已写入磁盘。
如果操作是读操作,中断将发出数据就绪的信号,处理程序将读取数据。请注意,idestart具有有关IDE设备的详细信息,并在正确的端口写入正确的值。如果这些outb语句中的任何一个是错误的,IDE将执行与我们所希望的不同的操作。编写设备驱动程序之所以具有挑战性,其中一个原因就是要正确处理这些细节。
Having added the request to the queue and started it if necessary, iderw must wait for the result. As discussed above, polling does not make efficient use of the CPU. Instead, iderw yields the CPU for other processes by sleeping, waiting for the interrupt handler to record in the buffers flags that the operation is done (4378-4379) . While this process is sleeping, xv6 will schedule other processes to keep the CPU busy.
将请求添加到队列并在必要时启动它之后,iderw必须等待结果。如上所述,轮询不能有效地利用CPU。相反,iderw通过休眠将CPU留给其他进程,等待中断处理程序在缓冲区的标志中记录操作已完成(4378-4379)。当这个进程处于休眠状态时,xv6会调度其他进程,让CPU保持忙碌。
Eventually, the disk will finish its operation and trigger an interrupt. trap will call ideintr to handle it (3424) . Ideintr (4304) consults the first buffer in the queue to find out which operation was happening. If the buffer was being read and the disk controller has data waiting, ideintr reads the data from a buffer in the disk controller into memory with insl (4317-4319) . Now the buffer is ready: ideintr sets B_VALID, clears B_DIRTY, and wakes up any process sleeping on the buffer (4321-4324) . Finally, ideintr must pass the next waiting buffer to the disk (4326-4328) .
最终,磁盘将完成其操作并触发中断。trap将调用ideintr来处理它(3424)。Ideintr(4304)查询队列中的第一个缓冲区以找出正在发生的操作。如果正在读取缓冲区并且磁盘控制器有数据等待,则ideintr使用insl(4317-4319)将数据从磁盘控制器中的缓冲区读取到内存中。现在缓冲区已经准备好了:ideintr设置B_VALID,清除B_DIRTY,并唤醒缓冲区中休眠的任何进程(4321-4324)。最后,ideintr必须将下一个等待缓冲区传递给磁盘(4326-4328)。
本站涵盖的内容、图片、视频等数据系网络收集,部分未能与原作者取得联系。若涉及版权问题,请联系我们删除!联系邮箱:ynstorm@foxmail.com 谢谢支持!