CS130 操作系统I Project 0 准备工作

aaaaa Lv3

Project: 基于PintOS的手搓操作系统!

整个学期的Project分为5个部分:

  • Project 0: 准备工作
  • Project 1: Threads | 进程
  • Project 2: User Programs | 用户程序
  • Project 3: Virtual Memory | 虚拟内存
  • Project 4: File Systems | 文件系统

每个部分基于前一个部分的工作完成,所以还请务必按照顺序!

学期内的Project是在学校的在线平台上完成,那里已经搭好了VM的环境,需要ssh远程过去写代码、跑调试。但是在假期内学校在线端口无法访问,Project需要通过在本地手动配置环境并部署来完成。接下来介绍的所有过程都基于本地Windows 11系统,从头开始配置环境、部署Project。


Project 0: 准备工作

安装与调试

由于我是Windows 11用户,之前听说在Windows上不能安装Docker,但是发现了Docker Desktop过后,Windows上也能轻松使用Docker了。虽然说本质上还是一种WSL(Windows Subsystem for Linux),但是省得我装一个VMWare或者直接在本机上装一个Ubuntu(事实上我都装了,希望后来者可以不用走这条弯路)。具体步骤如下:

安装Docker

官网链接下载,非苹果机的Windows用户选择 Download for Windows - AMD64,下载后按照提示正常安装即可;安装完成后打开,可能会出现要求安装WSL的命令行窗口,按任意键安装,大约需要3-5min完成;

下载PintOS源代码包

有两种方法:①按照学校提供的链接下载并解压(需要校内VPN访问),或者②从北大的Github仓库下拉:

1
git clone git@github.com:PKU-OS/pintos.git

在本地进行系统测试

打开Decker Desktop客户端,打开系统的命令行窗口,完成如下对话:

  • 将以下输入路径调整成实际安装路径后输入:

    1
    docker run -it --rm --name pintos --mount type=bind,source=absolute/path/to/pintos/on/your/host/machine,target=/home/PKUOS/pintos pkuflyingpig/pintos bash

    然后命令行应该会变成如下格式(具体内容可能不同):

    ps. 如果提示 fail to connect to the docker API,可以尝试挂梯子使用(先打开Decker Desktop)

    1
    root@9113da5c984f:~#

    这说明一个微型的Ubuntu系统正在你的电脑上运行!

  • 接下来键入:

    1
    pwd

    会有如下回话:

    1
    /home/PKUOS
  • 接下来键入:

    1
    ls

    会有如下回话:

    1
    pintos  toolchain
  • 以上对话如果均正常,那么接下来可以尝试启动系统了,键入:

    1
    2
    3
    4
    5
    cd pintos/src/threads/
    make
    cd build
    pintos --

    如果回话的最后几行类似于:

    1
    2
    3
    4
    5
    6
    7
    8
    Pintos hda1
    Loading............
    Kernel command line:
    Pintos booting with 3,968 kB RAM...
    367 pages available in kernel pool.
    367 pages available in user pool.
    Calibrating timer... 32,716,800 loops/s.
    Boot complete.

    那就说明你的PintOS系统在本地成功运行了!

  • 注:此时可以按 Ctrl + C关闭PintOS系统,然后按 Ctrl + D退出微型的Ubuntu系统。

  • 目前已经完成的架构,是在Windows上通过WSL和Docker建立了一个Ubuntu容器(Container),然后在这个Ubuntu容器内部通过QEMU模拟了一台x86计算机的硬件结构,然后在这台模拟的计算机上运行了PintOS系统,这个结构画出来就是这样的:

    1
    2
    3
    4
    5
    6
    Host OS(Windows / macOS / Linux)
    └── Docker
    └── Ubuntu Linux(容器里的用户态 Linux)
    └── QEMU(一个普通用户程序)
    └── 模拟的 32-bit x86 计算机(CPU, 内存, 磁盘等硬件)
    └── PintOS(操作系统)

在本地进行程序测试

尝试运行Project 1的本地test:

  • 打开任意终端,启动Ubuntu系统:

    1
    docker run -it --rm --name pintos --mount type=bind,source=absolute/path/to/pintos/on/your/host/machine,target=/home/PKUOS/pintos pkuflyingpig/pintos bash
    1
    root@9113da5c984f:~#
  • 进入 pintos/src/threads/build/目录:

    1
    cd pintos/src/threads/build/
    1
    root@4aedfa24dc44:~/pintos/src/threads/build#
  • 开始测试:

    1
    make check

    测试大约需要20~30s,看到输出结果最后类似于以下,说明你到目前为止的操作没有问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    pass tests/threads/alarm-single
    pass tests/threads/alarm-multiple
    pass tests/threads/alarm-simultaneous
    FAIL tests/threads/alarm-priority
    pass tests/threads/alarm-zero
    pass tests/threads/alarm-negative
    FAIL tests/threads/priority-change
    FAIL tests/threads/priority-donate-one
    FAIL tests/threads/priority-donate-multiple
    FAIL tests/threads/priority-donate-multiple2
    FAIL tests/threads/priority-donate-nest
    FAIL tests/threads/priority-donate-sema
    FAIL tests/threads/priority-donate-lower
    FAIL tests/threads/priority-fifo
    FAIL tests/threads/priority-preempt
    FAIL tests/threads/priority-sema
    FAIL tests/threads/priority-condvar
    FAIL tests/threads/priority-donate-chain
    FAIL tests/threads/mlfqs-load-1
    FAIL tests/threads/mlfqs-load-60
    FAIL tests/threads/mlfqs-load-avg
    FAIL tests/threads/mlfqs-recent-1
    pass tests/threads/mlfqs-fair-2
    pass tests/threads/mlfqs-fair-20
    FAIL tests/threads/mlfqs-nice-2
    FAIL tests/threads/mlfqs-nice-10
    FAIL tests/threads/mlfqs-block
    20 of 27 tests failed.
    ../../tests/Make.tests:26: recipe for target 'check' failed
    make: *** [check] Error 1

完成!

至此,你的安装和调试过程就已经全部完成了!


建库与合作

由于项目很大很难,所以强烈建议用Github完成:这样一方面完成了团队合作,另一方面也做了版本控制。仓库需要一定的管理,否则极容易发生混乱。建议的管理方式如下:

  • 初始仓库内仅有原始的PintOS源代码,存在 main分支下,以后不再修改
  • 每次开始一个新的Project时,继承上一个project的分支,建立新的分支,然后在新的分支内完成代码编写
  • 待上一个Project代码稳定后,保证代码不再修改后再建立新的分支,开始下一个Project。

记得频繁Commit!这样可以有效减少合作冲突!

由于笔者记不太住Git命令,所以在此附上常用的命令:

  • git status 查看仓库状态
  • git branch 查看当前在哪个分支下
  • git checkout proj1_threads 进入本地仓库已有的分支 proj1_threads
  • git checkout -b proj1_threads 复制当前分支所有内容进入新分支 proj1_threads,并进入新分支
  • git pull 拉取当前分支下所有内容
  • git add . 添加本地目录下所有文件进入暂存区
  • git commit -m "comments" -m "description" 提交暂存区内容到本地仓库(引号是命令的一部分)
  • git push -u origin proj1_threads 将本地仓库当前分支内容推送到远端仓库新建分支 proj1_threads(请保证本地仓库远端仓库名称一致!)
  • git push 将本地仓库当前分支内容推送到远端仓库对应的分支上

需要了解的内容

Pintos 目录简介

  • threads/
    • 基础内核的源代码,从Project 1开始你将修改此部分。
  • userprog/
    • 用户程序加载器的源代码,从Project 2开始你将修改此部分。
  • vm/
    • 一个几乎为空的目录。你将在Project 3中在此实现虚拟内存。
  • filesys/
    • 基础文件系统的源代码。从Project 2开始你将使用此文件系统,但直到Project 4才会修改它。
  • devices/
    • I/O设备接口的源代码:键盘、计时器、磁盘等。你将在Project 1中修改计时器实现。除此之外,你无需更改此部分。
  • lib/
    • 标准C库子集的实现。从此目录编译的代码从Project 2开始会同时被编译进Pintos内核及其下运行的用户程序中。在内核代码和用户程序中,均可使用 #include <...>符号包含此目录中的头文件。你基本不需要修改此部分。
  • lib/kernel/
    • 仅包含在Pintos内核中的C库部分。同时包含了一些你可以在内核代码中自由使用的数据类型的实现:位图、双向链表和哈希表。在内核中,可以使用 #include <...>符号包含此目录中的头文件。
  • lib/user/
    • 仅包含在Pintos用户程序中的C库部分。在用户程序中,可以使用 #include <...>符号包含此目录中的头文件。
  • tests/
    • 各项目的测试代码。如果有助于测试你的提交,你可以修改此处的代码。评分时,在运行测试前会将 tests/目录替换为原始版本。
  • examples/
    • 项目2开始使用的示例用户程序。
  • misc/utils/
    • 如果你尝试在自己的机器上使用Pintos,这些文件可能会派上用场。否则,你可以忽略它们。

更详细内容请参阅:Build and Run | Pintos

Build

要构建项目,只需要 cd进入某个项目目录(如 threads/, userprog/, vm/, filesys/等),然后键入指令:

1
make

等待20~30s即构建完成!

有关构建项目产生的文件具体用途,更详细内容请参阅:Building Pintos | Pintos

Run

要执行指令,可以按照以下规则输入指令:

1
pintos [工具选项] -- [内核参数]

其中,[工具选项] 部分为可选项(可以不写,也可以串接写很多个):

  • --bochs 使用Bochs代替默认的Qemu来模拟计算机;Bochs更适合Debug时使用,而Qemu大多数情况下跑得更快
  • --gdb 用Debug模式运行
  • -m 128 设置内存大小为128MB
  • -v 关闭VGA显示,仅输出结果
  • --bochs -t 使用终端作为VGA显示
  • -s 禁用输入输出,避免交互,仅输出结果

[内核参数] 部分可以有如下内容:

  • run alarm-multiple 指将 run alarm-multiple 作为参数传给PintOS系统,由系统响应这个指令,即运行指定的测试:alarm-multiple

所以总体上一个合法的输入可以是:

1
pintos -v -- run alarm-multiple

要想关闭进程,可以 Ctrl + C强制停止。

另外,获取更全的参数表可以键入:

1
pintos -h

更详细内容请参阅:Running Pintos | Pintos

Test

现在似乎只能一次性测试所有数据点,不过功能上完全覆盖测试单个数据点,只不过测试时间略长一点。测试过程如下:

  • 先完成项目构建,然后进入项目目录:

    1
    cd pintos/src/threads/build
  • 跑测试:

    1
    make check
  • 测试结果会直接显示出来,每个数据点具体的错误信息保存在具体项目目录下,如 pintos/src/threads/build/tests/threads

  • 从第二次测试开始,每次测试之前需要先手动删除该文件夹,如 pintos/src/threads/build/tests/threads

pintos/src/tests下的各个目录分别代表各个项目的测试程序目录,其中存有评测数据生成器和评测机等;可以手动修改部分评测机数据点进行本地测试,不过最终会以原数据点结果计分。

更详细的内容请参阅:Testing | Pintos

Debug

支持使用 printf()ASSERT来辅助Debug。

可以使用 Backtrace来Debug,具体操作详见Debugging | Pintos.

使用GDB来Debug:

  • 先正常启动Docker,然后在 终端1上启动Ubuntu系统;

  • 打开 终端2,键入:

    1
    docker exec -it pintos bash

    这样就成功在两个终端上进入同一个Ubuntu容器了。

  • 接下来在 终端1上先 make构建项目,然后进入项目目录(如 pintos/src/threads),键入带 --gdb选项的运行指令,如:

    1
    pintos --gdb -- run alarm-multiple

    然后 终端1会进入gdb模式,显示类似于这样的内容:

    1
    qemu-system-i386 -device isa-debug-exit -drive format=raw,media=disk,index=0,file=/tmp/2yFkc39zD1.dsk -m 4 -net none -nographic -gdb tcp::1234 -S
  • 接下来在 终端2上进入项目目录中的 build文件夹(如 pintos/src/threads/build),键入:

    1
    gdb kernel.o

    此时 终端2就成功进入gdb模式了,显示类似于这样的内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
    Copyright (C) 2018 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law. Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-linux-gnu".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>.
    Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from kernel.o...done.
    (gdb)
  • 接下来在 终端2中键入:

    1
    target remote localhost:1234

    此时 终端2成功连接上本机端口1234,显示类似于这样的内容:

    1
    2
    3
    Remote debugging using localhost:1234
    0x0000fff0 in ?? ()
    (gdb)

    这样gdb的配置就完成了。

  • 接下来就可以在 终端2上调试代码了。以下是一些gdb调试指令:

    • 程序控制

      • c / continue
        继续运行程序
      • si
        单步执行一条汇编指令
      • ni
        单步执行一条汇编指令(不进入调用)
      • s / step
        单步执行一行源码(进入函数)
      • n / next
        单步执行一行源码(不进入函数)
      • finish
        运行到当前函数返回
      • quit
        退出 GDB
    • 断点

      • b <function>
        在函数入口设置断点
      • b <file>:<line>
        在指定文件行号设置断点
      • info break
        查看所有断点
      • disable <n>
        禁用编号为 n 的断点
      • enable <n>
        启用编号为 n 的断点
      • delete <n>
        删除编号为 n 的断点
      • delete
        删除所有断点
    • 调用栈 / 执行上下文

      • bt
        显示调用栈(backtrace)
      • frame <n>
        切换到第 n 层栈帧
      • info frame
        查看当前栈帧信息
    • 变量 / 表达式

      • p <expr>
        打印变量或表达式
      • p/x <expr>
        以十六进制打印
      • set var <var>=<value>
        修改变量值
      • info locals
        查看当前函数的局部变量
      • info args
        查看当前函数参数
    • 寄存器

      • info registers
        查看所有寄存器
      • info registers eip esp ebp
        查看指定寄存器
      • p $eip
        打印寄存器值
    • 内存 / 指令查看

      • x/10i $eip
        查看当前指令地址开始的 10 条汇编
      • x/16x <addr>
        以十六进制查看内存
      • x/4w <addr>
        以 word 形式查看内存
      • disassemble <function>
        反汇编函数
    • 源码查看

      • list
        显示当前源码附近
      • list <function>
        显示函数源码
      • list <file>:<line>
        显示指定位置源码
    • 线程

      • info threads
        查看所有线程
      • thread <n>
        切换到指定线程
  • 终端2退出:键入 quit或按下 Ctrl + D,并确认退出

  • 终端1退出:可以先按下 Ctrl + A,松开后再按下 X关闭进程

更详细的内容请参阅:Debugging | Pintos

评分

在Ubuntu系统内、项目目录下(如 pintos/src/threads),在构建、运行结束后,可以键入:

1
make grade

以自动计算当前结果对应的分数和每个测试点的详细得分情况。

更详细的内容请参阅:Grading | Pintos

至此,Project 0,即写代码之前的必要准备就已经全部完成了!准备迎接代码之旅吧!


回到目录

  • 标题: CS130 操作系统I Project 0 准备工作
  • 作者: aaaaa
  • 创建于 : 2026-02-04 15:00:00
  • 更新于 : 2026-02-05 20:29:27
  • 链接: https://redefine.ohevan.com/2026/02/04/零基础速通:CS130 操作系统I_3/
  • 版权声明: 版权所有 © aaaaa,禁止转载。