优雅配置pintos

因为学校的操作系统课程设计要用这玩意,所以就要配置这个玩意
配置这玩意相对还是快的,但我也走了点弯路
如果图方便的话我还是建议用Docker方式安装
我的环境是WSL的Debian

我也会在github上更新我的实现代码

之前参考的任务说明是北大的pintos文档
但是学校给的代码是CS162最新的代码,里面代码结构变化很大
我决定还是保留之前写的lab1和lab2,但后面就只写学校的版本了
PKU-Docker
Berkeley-Docker

<0x00> 前置

需要配置WSL,然后安装Debian
目前的Debian版本是12
如果后面的版本遇到些gcc编译器问题的话就换老版本的Ubuntu LTS版本吧
然后需要git和稳定的维图诺·普莱维特·奈特沃克

<0x01> 拉取pintos仓库

git clone git://pintos-os.org/pintos-anon --depth=1

需要提前配置下git的proxy,不然可能会很慢

如果是ZJUT学生,做课设的话老师会给一个学校自己的gitlab链接
用那个链接克隆一个仓库即可
(其实克隆CS162的也可以,貌似链接年年换,这里就不贴了,Github一搜就有)

<0x02> 配置Debian需要的软件包

# 编译环境
sudo apt install make build-essential
# qemu模拟器
sudo apt install qemu
# 安装调试器
sudo apt install gdb

慢的话就换下apt的源

<0x03> 简单配置

修改./threads/Make.vars中的SIMULATOR

SIMULATOR = --qemu

然后修改下./utils/pintos

# 104行左右
$sim = "qemu" if !defined $sim;

20年之后的linux貌似不会提供stropts.h这个头文件
但我们直接系统里创建一个空的就可以了(注释掉也行)

sudo nano /usr/include/stropts.h

随便输入点注释的东西然后保存就可以

再注释./utils/squish-pty.c中下面的代码

// 大概在288行
if (isastream (slave))
{
	if (ioctl (slave, I_PUSH, "ptem") < 0
	|| ioctl (slave, I_PUSH, "ldterm") < 0)
	fail_io ("ioctl");
}

这样就可以了
(我不是很喜欢动path这种东西,网上说的其他修改貌似也都不是很关键)

<0x04> 尝试运行

在工作路径./src下面一条条执行

# 编译utils的文件
cd ./utils
make
# 回到./src
cd ..
# 编译内核
cd ./threads
make
# 进入编译好的内核文件夹
cd ./build
# 通过提供的脚本运行pintos
../../utils/pintos -- run alarm-multiple

理论上pintos就会运行了

<0x05> 在vscode中调试

这部分参考了这个仓库的配置文件

原本这个东西教程是在命令行用gdb调试
能调试但不方便
而vscode的C/C++插件的调试功能就是靠gdb实现的
我们能不能让vscode调用gdb连接到pintos进行调试呢?
答案是可以的,只是需要亿点配置

vscode连接wsl

这个在用vscode连接wsl的时候会跳提示,要求安装wsl的插件
安装就可以了
安装完会多很多插件,这是对的

点击左下角的图标,选择connect to WSL
然后vscode就会自己配置远程环境,只要WSL网络正常

安装C/C++插件

跟平时不同的是,我们需要给WSL安装C/C++插件,不过这很简单
前面跟往常一样,先是搜索C++,然后安装插件
不同的是安装后,会提示要不要在远程WSL那边安装,安装就可以了
然后vscode就会自己装了,等就可以了
(vscode全自动)

tasks.json和launch.json

这俩是什么

如果是经常用vscode写C++的用户,多少对这玩意有点印象
这两个东西算是调试控制脚本和编译控制脚本
tasks控制怎么启动应用,launch控制怎么启动调试程序
这两个东西一般是在./.vscode文件夹里面的
直接创建就好,vscode会自己识别的

如果理解的话可以跳过这部分直接从附录找写好的文件

配置tasks.json

创建tasks.json,然后输入这些东西

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "[Lab1] compile",
            "type": "shell",
            "command": "make",
            "options": {
                "cwd": "${workspaceFolder}/threads"
            }
        },
        {
            "label": "[Lab1] Run In GDB Mode",
            "type": "shell",
            "isBackground": true,
            "problemMatcher": [
                {
                    "pattern": [
                        {
                            "regexp": ".",
                            "file": 1,
                            "location": 2,
                            "message": 3
                        }
                    ],
                    "background": {
                        "activeOnStart": true,
                        "beginsPattern": ".",
                        "endsPattern": ".",
                    }
                }
            ],
            "dependsOn": [
                "[P1] compile"
            ],
            "command": "../../utils/pintos -v -k --gdb  -- run ${input:test_name}",
            "options": {
                "cwd": "${workspaceFolder}/threads/build"
            }
        }
    ],
    "inputs": [
        {
            "id": "test_name",
            "type": "promptString",
            "description": "Name of the Test to Debug"
        }
    ]
}

这里创建了两个task,一个负责编译,一个复制运行
如果是自己配置的话注意路径

配置launch.json

创建launch.json,输入下面的东西

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "[Lab1] Debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/threads/build/kernel.o",
            "miDebuggerServerAddress": "127.0.0.1:1234",
            "preLaunchTask": "[P1] Run Test in GDB mode",
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "text": "-enable-pretty-printing",
                    "description": "Enable pretty-printing for gdb",
                    "ignoreFailures": true
                },
                {
                    "text": "source -v ${workspaceFolder}/misc/gdb-macros",
                    "description": "Import Pintos GDB macros file",
                    "ignoreFailures": false
                }
            ],
            "symbolLoadInfo": {
                "loadAll": true,
                "exceptionList": ""
            }
        }
    ]
}

记得注意路径

尝试运行

首先在./thread/init.c里面找到main,打个断点,然后运行
理论上这时候运行会让你选配置文件,选我们创建的debug配置
这时候就像运行别的C++项目一样,开始debug,体验好多了

需要注意的是,上面的配置仅针对lab1,后面的可能需要单独配置
(后面的我还没开始写)

<0x06> 配置Test

因为没把pintos配置到path中,所以在./thread/build下执行make test会找不到pintos
有把pintos添加到path中就不用动这些东西
这时候就要修改./test下面的Make.tests文件

# 大概在55行
TESTCMD = ../../utils/pintos -v -k -T $(TIMEOUT)
TESTCMD += $(SIMULATOR)
TESTCMD += $(PINTOSOPTS)

这样就可以了

警钟长鸣:不要用Arch编译

如果使用Arch编译这个东西的话可能会遇到loader.bin的大小有128M
而不是正常的512字节
不只是WSL中Arch会出现这个问题,物理机Manjaro也会这样
具体原因不是很清楚,我怀疑是gcc版本问题
我测试过Ubuntu22的gcc11和Debian12的gcc12,这两个都可以成功编译
但Arch的是gcc14,可能较高的gcc版本导致编译行为不符合预期
不过我暂时还没尝试在Arch中使用gcc11编译过
(源码编译gcc时间太长了,就摸了)