持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
前言
接着上篇文章,这篇文章的主要内容也是结识一些概念,和实现功能做法等等,包括了 目录与常规文件,文件系统,磁盘访问等等,内容相对枯燥,就是我个人学习过程中的技术笔记与总结思考
目录与常规文件
我们文件系统中的File 结构体可以表示常规文件或目录。这两种类型的“文件”通过File 结构体中的type 字段来区分。文件系统以完全相同的方式管理常规文件和目录文件,因为它根本不解释与常规文件关联的数据块的内容,而文件系统将目录文件的内容解释为描述目录中的文件和子目录的一系列File 结构体。
文件系统中的超级块包含一个File 结构体(Super 结构体中的root 字段),用于保存文件系统根目录的元数据。此目录文件的内容是描述位于文件系统根目录中的文件和目录的一系列File 结构体。根目录中的任何子目录可能反过来包含更多表示子子目录的File 结构体,依此类推。
文件系统
本练习的目标不是让您实现整个文件系统,而是让您仅实现某些关键组件。特别是,您将负责将块读入块缓存并将其刷新回磁盘;分配磁盘块;将文件偏移映射到磁盘块;并在 IPC 接口中实现读取、写入和打开。由于您不会自己实现所有文件系统,因此熟悉提供的代码和各种文件系统接口非常重要。
磁盘访问
我们操作系统中的文件系统环境需要能够访问磁盘,但我们尚未在内核中实现任何磁盘访问功能。我们没有采用传统的“整体式”操作系统策略,即向内核添加IDE磁盘驱动程序以及必要的系统调用以允许文件系统访问它,而是将IDE磁盘驱动程序实现为用户级文件系统环境的一部分。我们仍然需要稍微修改内核,以便设置内容,以便文件系统环境具有实现磁盘访问本身所需的权限。
以这种方式在用户空间中实现磁盘访问很容易,只要我们依赖于轮询,基于“编程I / O”(PIO)的磁盘访问并且不使用磁盘中断。也可以在用户模式下实现中断驱动的设备驱动程序(例如,L3 和 L4 内核会执行此操作),但这更加困难,因为内核必须对设备中断进行字段处理,并将它们分派到正确的用户模式环境。
x86 处理器使用 EFLAGS 寄存器中的 IOPL 位来确定是否允许保护模式代码执行特殊的设备 I/O 指令,如 IN 和 OUT 指令。由于我们需要访问的所有IDE磁盘寄存器都位于x86的I / O空间中,而不是内存映射,因此为文件系统环境提供“I / O特权”是我们唯一需要做的事情,以便允许文件系统访问这些寄存器。实际上,EFLAGS 寄存器中的 IOPL 位为内核提供了一种简单的“全有或全无”方法,用于控制用户模式代码是否可以访问 I/O 空间。在我们的例子中,我们希望文件系统环境能够访问I/O空间,但我们不希望任何其他环境能够访问I/O空间。
Exercise 1. i386_init() identifies the file system environment by passing the type ENV_TYPE_FS to your environment creation function, env_create. Modify env_create() in env.c, so that it gives the file system environment I/O privilege, but never gives that privilege to any other environment.
if (type == ENV_TYPE_FS) {
env->env_tf.tf_eflags |= FL_IOPL_MASK;
}
检查传入类型,如果是ENV_TYPE_FS,则为其设置文件环境的IOPL位。
Question:你是否不得不执行其他任何操作来确保在随后从一个环境切换到另一个环境时正确保存和还原此 I/O 权限设置?为什么?
是的,因为轮询切换环境时,我们会找到一个最近的RUNABLE的环境然后调用env_run来实现切换环境。在env_run中我们调用了env_pop_tf()函数来保存环境的现场状态,其中就包括了我们设置的I/O权限。