XV6

在内核启动之后,需要有文件系统保存程序和数据,例如 shell 中所执行的外部指令:lsmkdirrmcp 等程序,以及用户所需的其他数据文件等。由于我们将 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)
  1. 第一个驱动器编号为 0,镜像文件使用的是 xv6.img ,格式为 raw-smp
  2. 第二个驱动器编号为 1,镜像文件使用的是 fs.img,格式为 raw

QEMUOPTS 中的 QEMUEXTRA 暂时没有定义,根据名字可知:读者可以根据自己的需要扩充其他额外的选项。

1. QEMU 仿真中的磁盘影像

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.imgfs.imgxv6memfs.img。其中:

  1. xv6.imgbootblockkernel 构成。
  2. fs.imgREADME.md$(UPROGS) 构成。
  3. xv6memfs.imgbootblockkernelmemfs 构成。

2. xv6.img

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

3. fs.img

磁盘镜像 fs.img 是通过 mkfs 工具完成的,相应的 Makefile 给规则如下:

fs.img: mkfs README.md $(UPROGS)
    ./mkfs fs.img README.md $(UPROGS)

也就是说 mkfsREADME.md$(UPROGS) 指定的那些文件创建出符合 XV6 文件系统格式的磁盘镜像。$(UPROGS) 给出的文件名对应于可以运行与 XV6 系统的可执行文件,我们会在学习了 XV6 的 $(OBJS) 内核主体代码之后,再来学习和分析这些 XV6 的应用程序。

我们用 du -sh -b fs.img 命令可知该磁盘文件系统的总容量为 512000 字节,相当于 1000 个 512 字节大小的盘块。

由于我们还没有学习 XV6 的文件系统格式,因此现在也无法分析 fs.img 的内容。之后我们会专门讨论 mkfs 工具的实现。

4. xv6memfs.img

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