提交 75a52115 编写于 作者: Y Yifan Wu

Fix section1 of code-intro7

上级 91f30c7a
......@@ -167,7 +167,7 @@
应用程序运行中,操作系统要支持应用程序的输出功能,并还能支持应用程序退出。这需要完成 ``sys_write`` 和 ``sys_exit`` 系统调用访问请求的实现。 具体实现涉及到内联汇编的编写,以及应用与操作系统内核之间系统调用的参数传递的约定。为了让应用在还没实现操作系统之前就能进行运行测试,我们采用了Linux on RISC-V64 的系统调用参数约定。具体实现可参看 :ref:`系统调用 <term-call-syscall>` 小节中的内容。 这样写完应用小例子后,就可以通过 ``qemu-riscv64`` 模拟器进行测试了。
写完应用程序后,还需实现支持多个应用程序轮流启动运行的操作系统。这里首先能把本来相对松散的应用程序执行代码和操作系统执行代码连接在一起,便于 ``qemu-system=riscv64`` 模拟器一次性地加载二者到内存中,并让操作系统能够找到应用程序的位置。为把二者连在一起,需要对生成的应用程序进行改造,首先是把应用程序执行文件从ELF执行文件格式变成Binary格式(通过 ``rust-objcopy`` 可以轻松完成);然后这些Binary格式的文件通过编译器辅助脚本 ``os/build.rs`` 转变变成 ``os/src/link_app.S`` 这个汇编文件的一部分,并生成各个Binary应用的辅助信息,便于操作系统能够找到应用的位置。编译器会把把操作系统的源码和 ``os/src/link_app.S`` 合在一起,编译出操作系统+Binary应用的ELF执行文件,并进一步转变成Binary格式。
写完应用程序后,还需实现支持多个应用程序轮流启动运行的操作系统。这里首先能把本来相对松散的应用程序执行代码和操作系统执行代码连接在一起,便于 ``qemu-system-riscv64`` 模拟器一次性地加载二者到内存中,并让操作系统能够找到应用程序的位置。为把二者连在一起,需要对生成的应用程序进行改造,首先是把应用程序执行文件从ELF执行文件格式变成Binary格式(通过 ``rust-objcopy`` 可以轻松完成);然后这些Binary格式的文件通过编译器辅助脚本 ``os/build.rs`` 转变变成 ``os/src/link_app.S`` 这个汇编文件的一部分,并生成各个Binary应用的辅助信息,便于操作系统能够找到应用的位置。编译器会把把操作系统的源码和 ``os/src/link_app.S`` 合在一起,编译出操作系统+Binary应用的ELF执行文件,并进一步转变成Binary格式。
操作系统本身需要完成对Binary应用的位置查找,找到后(通过 ``os/src/link_app.S`` 中的变量和标号信息完成),会把Binary应用拷贝到 ``user/src/linker.ld`` 指定的物理内存位置(OS的加载应用功能)。在一个应执行完毕后,还能加载另外一个应用,这主要是通过 ``AppManagerInner`` 数据结构和对应的函数 ``load_app`` 和 ``run_next_app`` 等来完成对应用的一系列管理功能。
......
......@@ -227,7 +227,7 @@
本章涉及的代码量相对较多,且与进程执行相关的管理还有直接的关系。其实我们是参考经典的UNIX基于索引的文件系统,设计了一个简化的有一级目录并支持创建/打开/读写/关闭文件一系列操作的文件系统。这里简要介绍一下在内核中添加文件系统的大致开发过程。
第一步是能够写出与文件访问相关的应用。这里是参考并简化了Linux的创建/打开/读写/关闭文件的系统调用,在用户态设计并实现这些系统调用的接口。前面每章都或多或少地添加或改变各种系统调用,所以,在用户态实现面向文件的这几个系统调用接口是比较容易的
第一步是能够写出与文件访问相关的应用。这里是参考了Linux的创建/打开/读写/关闭文件的系统调用接口,力图实现一个 :ref:`简化版的文件系统模型 <fs-simplification>` 。在用户态我们只需要遵从相关系统调用的接口约定,在用户库里完成对应的封装即可。这一过程我们在前面的章节中已经重复过多次,读者应当对其比较熟悉。其中最为关键的是系统调用可以参考 :ref:`sys_open 语义介绍 <sys-open>` ,此外我们还给出了 :ref:`测例代码解读 <filetest-simple>`
第二步就是要实现 easyfs 文件系统了。由于Rust语言的特点,我们可以在用户态实现 easyfs 文件系统,并在用户态完成文件系统功能的基本测试后,就可以不修改就嵌入到操作系统内核中。我们按照自底向上方的执行流程来介绍easyfs文件系统的具体实现。当然,有了文件系统的具体实现,还需要对上一章的操作系统内核进行扩展,实现与 easyfs 文件系统对接的接口,这样才可以让操作系统拥有一个简单可用的文件系统。带有文件系统的操作系统就可以提高应用开发体验和程序执行与互操作的灵活性,让应用获得文件系统带了的各种便利。
......
......@@ -130,6 +130,8 @@ Blocks 给出 ``os`` 目录也占用 8 个块进行存储。实际上目录也
打开与读写文件的系统调用
--------------------------------------------------
.. _sys-open:
文件打开
++++++++++++++++++++++++++++++++++++++++++++++++++
......@@ -194,6 +196,8 @@ Blocks 给出 ``os`` 目录也占用 8 个块进行存储。实际上目录也
在打开一个文件之后,我们就可以用之前的 ``sys_read/sys_write`` 两个系统调用来对它进行读写了。需要注意的是,常规文件的读写模式和之前介绍过的几种文件有所不同。标准输入输出和匿名管道都属于一种流式读写,而常规文件则是顺序读写和随机读写的结合。由于常规文件可以看成一段字节序列,我们应该能够随意读写它的任一段区间的数据,即随机读写。然而用户仅仅通过 ``sys_read/sys_write`` 两个系统调用不能做到这一点。
事实上,进程为每个它打开的常规文件维护了一个偏移量,在刚打开时初始值一般为 0 字节。当 ``sys_read/sys_write`` 的时候,将会从文件字节序列偏移量的位置开始 **顺序** 把数据读到应用缓冲区/从应用缓冲区写入数据。操作完成之后,偏移量向后移动读取/写入的实际字节数。这意味着,下次 ``sys_read/sys_write`` 将会从刚刚读取/写入之后的位置继续。如果仅使用 ``sys_read/sys_write`` 的话,则只能从头到尾顺序对文件进行读写。当我们需要从头开始重新写入或读取的话,只能通过 ``sys_close`` 关闭并重新打开文件来将偏移量重置为 0。为了解决这种问题,有另一个系统调用 ``sys_lseek`` 可以调整进程打开的一个常规文件的偏移量,这样便能对文件进行随机读写。在本教程中并未实现这个系统调用,因为顺序文件读写就已经足够了。顺带一提,在文件系统的底层实现中都是对文件进行随机读写的。
.. _filetest-simple:
下面我们从本章的测试用例 ``filetest_simple`` 来介绍文件系统接口的使用方法:
......
......@@ -4,7 +4,7 @@
本节导读
---------------------------------------
本节我们介绍一个简易文件系统实现 easy-fs。作为一个文件系统而言,它的磁盘布局(为了叙述方便,我们用磁盘来指代一系列持久存储设备)体现在磁盘上各扇区的内容上,而它解析磁盘布局得到的逻辑目录树结构则是通过内存上的数据结构来访问的,这意味着它要同时涉及到对磁盘和对内存的访问。它们的访问方式是不同的,对于内存直接通过一条指令即可直接读写内存相应的位置,而磁盘的话需要用软件的方式向磁盘发出请求来间接进行读写。此外,我们也要特别注意哪些数据结构是存储在磁盘上,哪些数据结构是存储在内存中的,这样在实现的时候才不会引起混乱。
本节我们介绍一个简易文件系统实现 easy-fs。作为一个文件系统而言,它的磁盘布局(为了叙述方便,我们用磁盘来指代一系列持久存储设备)体现在磁盘上各扇区的内容上,而它解析磁盘布局得到的逻辑目录树结构则是通过内存上的数据结构来访问的,这意味着它要同时涉及到对磁盘和对内存的访问。它们的访问方式是不同的,对于内存直接通过一条指令即可直接读写内存相应的位置,而磁盘的话需要用软件的方式向磁盘发出请求来间接进行读写。因此,我们也要特别注意哪些数据结构是存储在磁盘上,哪些数据结构是存储在内存中的,这样在实现的时候才不会引起混乱。
松耦合模块化设计思路
---------------------------------------
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册