在内核启动之后,需要有文件系统保存程序和数据,例如 shell 中所执行的外部指令:ls、mkdir、rm、cp 等程序,以及用户所需的其他数据文件等。由于我们将 XV6 运行于 QEMU 仿真环境,因此需要把相应的文件系统内容形成磁盘镜像文件。
XV6 中有两个磁盘镜像,一个是 xv6.img ,用于存放 XV6 操作系统;另一个是 fs.img,作为磁盘文件系统的镜像。当使用 QEMU 仿真器运行 XV6 时,将使用上述两个镜像。Makefile 中定义了 QEMUOPTS 变量,用作 QEMU 仿真参数,其中使用 -driver 选项定义了两个磁盘驱动器:
QEMUOPTS = -drive file=fs.img,index=1,media=disk,format=raw -drive file=xv6.img,index=0,media=disk,format=raw -smp $(CPUS) -m 512 $(QEMUEXTRA)
xv6.img ,格式为 raw-smpfs.img,格式为 rawQEMUOPTS 中的 QEMUEXTRA 暂时没有定义,根据名字可知:读者可以根据自己的需要扩充其他额外的选项。
XV6 有三种启动方式,在 Makefile 中相关的代码如下:
qemu: fs.img xv6.img
$(QEMU) -serial mon:stdio $(QEMUOPTS)
qemu-memfs: xv6memfs.img
$(QEMU) -drive file=xv6memfs.img,index=0,media=disk,format=raw -smp $(CPUS) -m 256
qemu-nox: fs.img xv6.img
$(QEMU) -nographic $(QEMUOPTS)
当使用 make qemu 启动系统时,会弹出一个新窗口。而 make qemu-nox 虽然还是使用上面的选项,但是多了一个 -nographic 选项,因此不会弹出额外的窗口,而是直接在现有终端下显示 XV6 的输出。make qemu-memfs 则是使用内存盘来保存整个文件系统。
这里用到了三个磁盘影像 xv6.img、fs.img、xv6memfs.img。其中:
xv6.img 由 bootblock 和 kernel 构成。fs.img 由 README.md 和 $(UPROGS) 构成。xv6memfs.img 由 bootblock 和 kernelmemfs 构成。从 Makefile 有关 xv6.img 的生成规则看,xv6.img 依赖于启动扇区 bootblock 以及 kernel。
xv6.img: bootblock kernel
dd if=/dev/zero of=xv6.img count=10000
dd if=bootblock of=xv6.img conv=notrunc
dd if=kernel of=xv6.img seek=1 conv=notrunc
磁盘镜像 fs.img 是通过 mkfs 工具完成的,相应的 Makefile 给规则如下:
fs.img: mkfs README.md $(UPROGS)
./mkfs fs.img README.md $(UPROGS)
也就是说 mkfs 将 README.md 和 $(UPROGS) 指定的那些文件创建出符合 XV6 文件系统格式的磁盘镜像。$(UPROGS) 给出的文件名对应于可以运行与 XV6 系统的可执行文件,我们会在学习了 XV6 的 $(OBJS) 内核主体代码之后,再来学习和分析这些 XV6 的应用程序。
我们用 du -sh -b fs.img 命令可知该磁盘文件系统的总容量为 512000 字节,相当于 1000 个 512 字节大小的盘块。
由于我们还没有学习 XV6 的文件系统格式,因此现在也无法分析 fs.img 的内容。之后我们会专门讨论 mkfs 工具的实现。
与 xv6.img 由启动扇区 bootblock 和内核 kernel 组成不同,xv6mem.img 还包含了完整的磁盘文件系统的内容(即 kernelmemfs = kernel + fs.img)。
xv6memfs.img: bootblock kernelmemfs
dd if=/dev/zero of=xv6memfs.img count=10000
dd if=bootblock of=xv6memfs.img conv=notrunc
dd if=kernelmemfs of=xv6memfs.img seek=1 conv=notrunc