Why

操作系统这门课实验的终极目标应该是能独立写出一个可以工作的系统内核,但是因为课程时间有限, 权衡起见直接用一个已经写好的内核,通过修改其源码实践一些操作系统理论是一个不错的选择。 在这里我们选择 PintOS 作为这一平台,因为前人的工作,PintOS 包含了很多测试和工具, 有相对比较成熟的打分和课程机制。

PintOS是一个操作系统,作为操作系统,其下管理硬件资源,其上承载应用软件,本实验课主要侧重 前者,而硬件资源是一个抽象的概念,它既可以指物理机,也可以指虚拟机,本实验采用 qemu 虚拟机 作为硬件资源。

我们的目标是,让 PintOS 在 qemu 虚拟机上运行起来,并修改其源码,使用一些课程中的理论让其对硬件资源的 使用更有效率,进而达到知行合一的目的。期间可能还会用到类似 gdb 这样的调试工具,之后我们将分别讨论。

32-bit Linux

尝试在 Mac 下搭建工作环境(理论上肯定是可以移植的),包括一些别人改过的所谓在 pintos-mac 下折腾了很久, 在 CalTech 的 OS 课程页面上发现了下面一段话:

Students are strongly advised to develop Pintos on a 32-bit Linux platform. Pintos has been most extensively tested on GNU/Linux, in particular the Debian and Ubuntu distributions.

It is not designed to install under any form of Windows, including with Cygwin.

Similarly, Mac OS X has enough differences that it is extremely difficult to get Pintos working on it; therefore Mac OS X is not supported as a platform for Pintos.

这是在实验文档说明中唯一明确说说明了关于操作系统环境的,表示感谢!理论上条条大路通罗马,但每条路的成本和收益有限, 最佳实践或者最佳平台可以省不少事,让人更专注于目标。

处理配置

下载解压源码

root@vultr:~/os# wget https://web.stanford.edu/class/cs140/projects/pintos/pintos.tar.gz
root@vultr:~/os# tar -xaf pintos.tar.gz  # 下载解压源码
root@vultr:~/os# ls
pintos      pintos.tar.gz

root@vultr:~/os/pintos/src/utils# pwd
/root/os/pintos/src/utils

utils 目录下主要是一些脚本工具,重点注意 pintospintos-gdb 这两个,前者是 perl 脚本,后者是 shell 脚本。 pintos 里面包含了 启动什么虚拟机,启动虚拟机的选项,主要函数如下:

parse_command_line ();
prepare_scratch_disk ();
find_disks ();
run_vm ();
finish_scratch_disk ();

环境变量

root@vultr:~/os/pintos/src/utils# vim /root/.bashrc # 添加环境变量
root@vultr:~/os/pintos/src/utils# source /root/.bashrc
root@vultr:~/os/pintos/src/utils# which pintos
/root/os/pintos/src/utils/pintos

gdb和虚拟机

root@vultr:~/os/pintos/src/utils# vim pintos-gdb # 修改 gdb-macros 的路径
# GDBMACROS=/root/os/pintos/src/misc/gdb-macros

root@vultr:~/os/pintos/src/utils# vim pintos     # 修改默认 sim = "qemu"

gdb-macros 里面包含了一些用来调试 Pintos 的宏。我们将使用 qemu 作为默认的虚拟机进行实验。

build & run 内核

root@vultr:~/os/pintos/src# cd threads/
root@vultr:~/os/pintos/src/threads# make clean
rm -rf build
root@vultr:~/os/pintos/src/threads# make

mkdir -p build/devices
...

root@vultr:~/os/pintos/src/threads# cd build/
root@vultr:~/os/pintos/src/threads/build# pintos -- run alarm-multiple

Use of literal control characters in variable names is deprecated at /root/os/pintos/src/utils/pintos line 911.
Prototype mismatch: sub main::SIGVTALRM () vs none at /root/os/pintos/src/utils/pintos line 935.
Constant subroutine SIGVTALRM redefined at /root/os/pintos/src/utils/pintos line 927.
qemu -hda /tmp/iQ2iIKpdUX.dsk -m 4 -net none -nographic -monitor null
Can't exec "qemu": No such file or directory at /root/os/pintos/src/utils/pintos line 923.
command failed

这里我们看到执行失败了,原因是找不到 qemu 命令,我们把 utils/pintos 脚本中的 qemu 命令改为 qemu-system-i386

root@vultr:~/os/pintos/src/threads/build# diff ../../utils/pintos /root/pintos/utils/pintos

582c582
<   print BOCHSRC "display_library: nogui\n" if $vga eq 'none';
---
>   print BOCHSRC "display_library: sdl\n" if $vga eq 'none';
623c623
<     my (@cmd) = ('qemu');
---
>     my (@cmd) = ('qemu-system-i386');

root@vultr:~/os/pintos/src/threads/build# vim ../../utils/pintos # 修复
root@vultr:~/os/pintos/src/threads/build# diff ../../utils/pintos /root/pintos/utils/pintos
582c582
<   print BOCHSRC "display_library: nogui\n" if $vga eq 'none';
---
>   print BOCHSRC "display_library: sdl\n" if $vga eq 'none';

重新 build & run:

root@vultr:~/os/pintos/src/threads# make clean
rm -rf build
root@vultr:~/os/pintos/src/threads# make

mkdir -p build/devices
...

root@vultr:~/os/pintos/src/threads# cd build/
root@vultr:~/os/pintos/src/threads/build# ls
devices  kernel.bin  kernel.o  lib  loader.bin      Makefile  tests  threads
root@vultr:~/os/pintos/src/threads/build# pintos -- run alarm-multiple
Use of literal control characters in variable names is deprecated at /root/os/pintos/src/utils/pintos line 911.
Prototype mismatch: sub main::SIGVTALRM () vs none at /root/os/pintos/src/utils/pintos line 935.
Constant subroutine SIGVTALRM redefined at /root/os/pintos/src/utils/pintos line 927.

qemu-system-i386 -hda /tmp/2pA_JG66a8.dsk -m 4 -net none -nographic -monitor null

WARNING: Image format was not specified for '/tmp/2pA_JG66a8.dsk' and probing guessed raw.
Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
Specify the 'raw' format explicitly to remove the restrictions.

PiLo hda1
Loading...........
Kernel command line: run alarm-multiple
Pintos booting with 3,968 kB RAM...
367 pages available in kernel pool.
367 pages available in user pool.
Calibrating timer...  419,020,800 loops/s.
Boot complete.
Executing 'alarm-multiple':
(alarm-multiple) begin
(alarm-multiple) Creating 5 threads to sleep 7 times each.
(alarm-multiple) Thread 0 sleeps 10 ticks each time,
(alarm-multiple) thread 1 sleeps 20 ticks each time, and so on.
(alarm-multiple) If successful, product of iteration count and
(alarm-multiple) sleep duration will appear in nondescending order.
(alarm-multiple) thread 0: duration=10, iteration=1, product=10
(alarm-multiple) thread 0: duration=10, iteration=2, product=20
(alarm-multiple) thread 1: duration=20, iteration=1, product=20

# 此处部分输出省略

(alarm-multiple) end
Execution of 'alarm-multiple' complete.

这里 run 主要是 tests 目录下的一些测试,我们的目标就是通过这些测试。 可以在本目录下运行 build check 查看所有测试的通过情况。

调试

可以使用 pintos-gdb 工具调试内核,该工具会启动 gdb,利用 gdb-macro (之前修改过路径)进行一些调试

root@vultr:~/os/pintos/src/threads/build# pintos-gdb kernel.o

gdb 的使用方法可以参考归纳。

注意的点

  • 有最佳实践就按照最佳实践走,可以避免很多坑
  • 遇到问题要从下往上阅读报错提醒,然后查看代码中可能出现的问题