当前位置: 首页 > news >正文

linux2.6 和 unix-v6 源码实验

《计算机操作系统》、《Operating Systems: Three Easy Pieces》、《UNIX环境高级编程》

MIT6.828: Operating System Engineering
https://pdos.csail.mit.edu/6.828/2019/schedule.html

基于 Linux 内核(如 2.6.11.12 或 2.6.39)做学习或者实验,想从内核启动的源代码开始分析整个启动过程,我可以帮你从入口函数逐步展开


🧠 一、内核启动流程总览(x86 架构)

对于 QEMU 启动的 x86 架构内核(bzImage),内核的启动过程主要分以下阶段:

Bootloader → Real Mode Entry → Protected Mode Setup → Paging → start_kernel → rest_init → kernel_thread(init)

🧩 二、代码入口文件和路径说明

阶段文件位置关键函数
实模式入口arch/x86/boot/header.S_start(由 bootloader 跳转)
保护模式设置arch/x86/boot/compressed/head_32.Sstartup_32
解压完成跳转arch/x86/kernel/head.Sstartup_32(再次)
内核 C 语言入口init/main.cstart_kernel 🟢
最终用户态进程init/main.cinit()/init 程序

🚀 三、最核心起点:start_kernel

路径:init/main.c

asmlinkage void __init start_kernel(void)

这个函数是内核初始化最重要的部分,从这个函数开始,Linux 内核进入了 C 语言世界。


🧩 四、start_kernel() 内部主要步骤(精简版)

  1. 设置中断、禁用中断
  2. early_printk 初始化(早期调试信息输出)
  3. 设置内存页管理
  4. 初始化调度器、时间子系统
  5. 初始化中断控制器
  6. 初始化文件系统、字符设备、网络协议栈
  7. 调用 rest_init() → 进入内核线程

🔁 五、从 start_kernel 到用户空间

路径(重要流程)如下:

start_kernel()└── rest_init()├── kernel_thread(kernel_init)│    ├── kernel_init_freeable()│    │     ├── prepare_namespace()│    │     └── init_post() → 启动 /init└── cpu_idle()   // 空转CPU

🧪 六、你可以重点阅读的源码文件(按顺序):

文件路径用途说明
arch/x86/boot/header.S实模式入口,设置堆栈、跳转到保护模式
arch/x86/kernel/head.S保护模式下的入口,设置分页等
init/main.cstart_kernel() 是所有 C 代码的起点
kernel/sched.c调度器初始化
init/do_mounts.c挂载根文件系统
fs/exec.c / init/initramfs.c加载 init 程序

📌 建议阅读顺序(推荐)

  1. arch/x86/kernel/head.S → 看 startup_32
  2. init/main.c → 看 start_kernel()
  3. 跟踪调用 rest_init()kernel_thread()kernel_init()init_post()
  4. 查看 init/do_mounts.c → 如何挂载 rootfs
  5. 查看 fs/exec.c → 如何加载 /init 用户态程序(或 busybox)

🧰 想动手调试?

你可以使用 QEMU 启动内核,加上 GDB 调试:

qemu-system-i386 \-kernel bzImage \-initrd initramfs.cpio.gz \-append "console=ttyS0" \-nographic \-s -S

然后用 GDB 连接:

gdb vmlinux
(gdb) target remote :1234

这样可以在 start_kernelstartup_32 处下断点单步分析。


下面是一个完整的 Dockerfile,用于在 Docker 容器中编译 Linux 2.6.39 内核并支持使用 QEMU 启动调试:


✅ Dockerfile(x86_64 架构,适用于 QEMU 调试)

FROM ubuntu:20.04ENV DEBIAN_FRONTEND=noninteractive# 安装依赖
RUN apt-get update && \apt-get install -y \build-essential \gcc-4.6 g++-4.6 \libncurses5-dev \bc \kmod \cpio \flex \bison \libelf-dev \qemu qemu-system-x86 \busybox \initramfs-tools \wget \git \vim \gdb \python3 \ca-certificates && \rm -rf /var/lib/apt/lists/*# 设置默认 gcc 为 4.6
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 && \update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 60WORKDIR /root# 可选:自动下载 Linux 内核源码(也可以手动挂载)
# RUN wget https://cdn.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.tar.xz && \
#     tar -xf linux-2.6.39.tar.xz && \
#     mv linux-2.6.39 linux# 拷贝本地源码挂载路径(外部 -v 映射)
VOLUME ["/root/linux"]CMD ["/bin/bash"]

✅ 构建镜像

docker build -t linux2639-env .

✅ 运行容器(挂载你的源码目录)

假设你已经解压了内核源码到当前目录:

docker run -it --rm -v $PWD/linux-2.6.39:/root/linux linux2639-env

✅ 容器内操作步骤

cd linux# 使用默认配置
make defconfig# 编译内核(vmlinux 和 bzImage)
make -j$(nproc)

编译静态链接的 busybox

bash

git clone -b 1_21_stable https://github.com/mirror/busybox.git
cd busybox
make defconfig
# 设置为静态链接
sed -i 's/^# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
make -j$(nproc)

✅ 构建最小 rootfs

mkdir -p initramfs/{bin,sbin,etc,proc,sys,dev}
cp busybox initramfs/bin/
chmod +x initramfs/bin/busybox
cd initramfs/bin
for cmd in $(./busybox --list); do ln -s busybox $cmd; done# 创建 /init 脚本
cat > initramfs/init << 'EOF'
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
echo "Welcome to Linux 2.6.39!"
exec /bin/sh
EOF
chmod +x initramfs/init# 创建 /dev/console
sudo mknod -m 600 initramfs/dev/console c 5 1# 打包成 initramfs
cd initramfs
find . | cpio -o --format=newc | gzip > ../initramfs.cpio.gz

✅ 启动内核(QEMU)

qemu-system-x86_64 \-kernel /root/linux/arch/x86/boot/bzImage \-initrd /root/initramfs.cpio.gz \-append "root=/dev/ram rdinit=/init console=ttyS0" \-nographic

✅ 使用 GDB 远程调试(可选)

qemu-system-x86_64 \-kernel /root/linux/arch/x86/boot/bzImage \-initrd /root/initramfs.cpio.gz \-append "root=/dev/ram rdinit=/init console=ttyS0" \-nographic -s -S

然后在另一个终端:

docker exec -it <容器名或ID> bash
cd /root/linux
gdb vmlinux
(gdb) set architecture i386:x86-64
(gdb) target remote :1234
(gdb) b start_kernel
(gdb) c

✅ 小贴士

  • vmlinux:用于调试(含符号)
  • bzImage:用于启动
  • 如果需要支持 ARM、MIPS 等架构,需要补充交叉工具链 + QEMU 环境

注意事项
内核的符号表文件一般是编译时生成的 vmlinux,而不是压缩过的 bzImage。确保你用 GDB 载入的是 vmlinux。

确保内核配置中开启了调试符号(编译内核时加 CONFIG_DEBUG_INFO=y)。

你可以在 make menuconfig 里配置或直接在 .config 里加。


VSCode + GDB 可以可视化调试 Linux 内核源码,并能看到源代码、变量、寄存器、内存等信息。前提是你的 vmlinux 文件必须是 带调试信息的未剥离(not stripped) 文件 —— 你已经满足了这一点:

vmlinux: ELF 64-bit LSB  executable, x86-64, ... not stripped

🔍 你能看到什么?

使用 VSCode + GDB(通过 launch.json 远程调试) 时,你可以看到:

项目是否能看到说明
源代码行号 + 断点高亮当前执行行,支持设置断点
寄存器值显示 CPU 通用寄存器
当前栈帧显示函数调用栈
局部变量、参数自动解析变量名和值
内存内容(hex)支持查看/编辑内存
汇编指令视图支持

VSCode 会在调试面板中提供图形方式查看这些内容,非常直观。


🧩 准备工作

确保你已经有这些东西:

✅ 1. 带调试信息的 vmlinux

你已经有了:

vmlinux: ELF 64-bit ... not stripped

✅ 2. 启动 QEMU 并开放 gdb 端口

你需要这样启动 QEMU:

qemu-system-x86_64 \-kernel arch/x86/boot/bzImage \-append "console=ttyS0" \-nographic \-s -S

解释:

  • -s = -gdb tcp::1234 (监听端口)
  • -S = 上电暂停,等 GDB 连接

⚙️ 3. 创建 VSCode 的调试配置

在你的 VSCode 项目目录中,添加 .vscode/launch.json 文件:

{"version": "0.2.0","configurations": [{"name": "Debug Linux Kernel","type": "cppdbg","request": "launch","program": "${workspaceFolder}/linux-2.6.39/vmlinux","miDebuggerServerAddress": "localhost:1234","miDebuggerPath": "/usr/bin/gdb","stopAtEntry": true,"cwd": "${workspaceFolder}/linux-2.6.39","externalConsole": false,"MIMode": "gdb","setupCommands": [{"description": "Enable pretty-printing","text": "-enable-pretty-printing","ignoreFailures": true},{"text": "set architecture i386:x86-64"}],"sourceFileMap": {"/home/you/linux-2.6.39": "${workspaceFolder}/linux-2.6.39"}}]
}

说明:

字段含义
program你的 vmlinux 文件路径
miDebuggerPathGDB 路径(确保支持多架构)
miDebuggerServerAddressQEMU 提供的 gdb 端口
stopAtEntry调试时暂停在入口函数
set architecture设置为 64 位架构

🚀 调试步骤

  1. 编译 Linux 内核(保留符号)
  2. 用 QEMU -s -S 启动内核(等 GDB)
  3. 在 VSCode 中按 F5 启动调试
  4. 看到源码、调试面板、可视化变量/堆栈

📷 效果图预览(预期)

👉 如果设置正确,你会看到 VSCode 显示如下内容:

▶ start_kernel() at init/main.c:457printk(KERN_INFO "Linux version %s\n", linux_banner);

左侧:变量、栈帧、寄存器;
中间:源码窗口 + 当前行;
右侧:控制台调试信息。


❓可能踩坑提示

问题原因
GDB 无法定位源码你的 vmlinux 被 strip 掉了,或源码路径不匹配
VSCode 看不到变量编译器优化过强,-O2/-O3 会内联和移除变量
无法连接QEMU 没用 -s -S,或端口不对
启动就崩溃bzImagevmlinux 不匹配或命令行出错

✅ 总结

可以通过 VSCode + GDB 实现 Linux 2.6.x 的源码级图形调试,能看到源码、变量、寄存器,非常适合研究内核启动过程。


同理,可以编译 unix-v6 (https://github.com/mit-pdos/xv6-public.git)

以下是使用 xv6‑public(xv6 的 x86 版本)在 Ubuntu/Linux 上安装、编译、运行、调试的详细中文指南。如果你想使用 RISC‑V 版本(xv6‑riscv),后续内容里也有说明。


1. 安装前提

  • 操作系统:Ubuntu 18.04/20.04 或其他主流 Linux 发行版
  • 工具集:Git、GNU C/C++ 编译器、makeqemu-system-i386(x86 版本)
  • 若系统为 64 位,且构建结果为 32-bit binary,则需安装多重架构支持(gcc-multilib

可使用以下命令批量安装:

sudo apt update
sudo apt install git build-essential qemu qemu-system-i386 gcc-multilib

确保 qemu-system-i386 可用于运行 xv6(x86 ELF 格式)([博客园][1], [GitHub][2], [GitHub][3])。


2. 获取源代码

从 MIT 官方仓库克隆 xv6-public:

git clone https://github.com/mit-pdos/xv6-public.git
cd xv6-public

该版本对应 MIT 6.828 课程使用版本,是学习 Unix V6 系统设计的现代实现镜像([pdos.csail.mit.edu][4])。

⚠️ MIT 已停止维护 x86 分支,建议转向 xv6‑riscv。如你坚持使用该版本,仍可继续使用,但未来建议迁移平台。


3. 编译 xv6

在 xv6-public 根目录下运行:

make

此命令执行以下工作:

  • 使用当前系统的 gcc 编译汇编文件与 C 源码
  • 链接生成 32-bit ELF 格式的 xv6 内核镜像:kernel 文件
  • 最终调用 qemu-system-i386 启动模拟器(若指定为 make qemu)([GitHub][2], [知乎专栏][5])

若系统默认执行不了 make qemu,请检查并使用 make qemu-nox(无图形 GUI)运行。


4. 启动 xv6

编译完成后,使用以下命令启动:

make qemu-nox

会在终端进入 xv6 shell 环境,如下所示:

init: starting sh
$

在 shell 中可以执行命令,例如 ls 会列出初始文件系统中的内容(README、各示例程序)([博客园][1])。

退出模拟器,可以按 Ctrl­a 然后 x


5. 常用命令对照表

操作命令示例
编译系统(清理后重编译)make clean && make
仿真启动 xv6make qemumake qemu-nox
启动 shell 并交互运行make qemu(默认进入 shell)
调试 / 设置断点(QEMU + GDB)make qemu-gdb + i386-elf-gdb
查看源代码打印版 PDFmake pdf, 编译成可打印的源码列表

6. 调试技巧

  • 使用 CTRL‑P 在 xv6 shell 打印进程状态(相当于 ps
  • 若想调试流程可在 kernel/ 下设置断点,法国 QEMU 可附带 GDB:
make qemu-gdb

然后使用 i386-elf-gdb 连接:

i386-elf-gdb kernel
(gdb) target remote localhost:26000

可以观察寄存器、设置断点、单步执行等([pdos.csail.mit.edu][6], [GitHub][7], [知乎专栏][5], [zhayujie.com][8], [博客园][1])。


7. xv6‑public vs xv6‑riscv 差异介绍

  • xv6‑public(x86 版本):

    • 面向 Intel x86 架构,使用 ELF 格式
    • 已停止 MIT 官方维护,功能稳定
    • 可在 Ubuntu 直装,编译方式以上说明
  • xv6‑riscv(RISC‑V 版本):

    • 用于 MIT 6.1810 课程,适用于 RISC‑V 指令集
    • 编译需安装 riscv-gnu-toolchain 和针对 RISC‑V 的 qemu(qemu-system-riscv64)
    • 运行方式略同:
git clone https://github.com/mit-pdos/xv6-riscv.git
make
make qemu

运行前请确保已安装 riscv64-linux-gnu-gccqemu-system-riscv64 等([bilibili.com][9], [pdos.csail.mit.edu][4], [GitHub][10])。


8. 教学资源与实验模板支持

  • MIT 6.828 提供一系列基于 xv6 的实验,包括 system calls、文件系统、调度器等
  • 学习资源包括 xv6-book(Rev11 版本 ~99 页)、源码手册、实验要求等
  • 推荐通过分支 xv6-labs-2020 来获取实验材料,并使用 make grademake handin 提交练习作业([pdos.csail.mit.edu][6], [维基百科][11])。

✅ 总结建议

  • 项目:xv6-public

    • 最基本的 MIT xv6 内核,在多核 x86 环境下静态编译、运行
    • 使用 make 编译、make qemu 运行,适合初步学习 Unix 系统机制
  • 工业路径建议

    • 若你落脚于现代机器,建议使用 xv6-riscv(支持 MIT 官方维护,也便于迁移和扩展)
    • 体验实验任务时结合 xv6-labs-2020 的指令完成课堂作业

无论你是想 阅读 xv6 官方注释书深入理解 Unix V6 源码逻辑、还是 实现 kid‑OS 实验系统功能,xv6-public 和 xv6-riscv 都是很好的起点!


xv6‑RISC‑V 是什么?🔧

特性描述
目标一个基于 RISC‑V 平台重写的教学操作系统,源自 MIT 的 xv6(x86 分支已于 2018 年停止维护)([pdos.csail.mit.edu][1])
灵感来源模仿 UNIX 第六版的内部设计风格,使用 ANSI C 编写,面向现代多核 RISC‑V 架构
教学用途支持 MIT 操作系统课程(6.828 / 6.1810),配有精炼的教材,包括进程、中断、分页、文件系统、并发控制等主题

一、准备环境(以 Ubuntu 22.04 为例)

  1. 安装 RISC‑V 工具链
    包括 riscv64-unknown-elf-gcc, riscv64-unknown-elf-ld, libc 等。可通过源码编译(推荐)或使用预编译版本:

    sudo apt-get update
    sudo apt-get install autoconf automake gawk libmpc-dev libmpfr-dev \libgmp-dev build-essential bison flex texinfo gperf libtool patchutils zlib1g-dev
    git clone --depth 1 https://github.com/riscv/riscv-gnu-toolchain
    cd riscv-gnu-toolchain
    ./configure --prefix=$HOME/riscv
    make linux -j$(nproc)
    export PATH=$HOME/riscv/bin:$PATH
    
  2. 安装 QEMU 的 RISC‑V 模拟器,至少支持 riscv64-softmmu 架构:

    sudo apt-get install libglib2.0-dev libpixman-1-dev ninja-build
    git clone --depth 1 https://github.com/qemu/qemu.git
    cd qemu
    ./configure --target-list=riscv64-softmmu --disable-docs
    make -j$(nproc)
    sudo make install
    
  3. 获取 xv6‑RISC‑V 源码并运行

    git clone https://github.com/mit-pdos/xv6-riscv.git
    cd xv6-riscv
    make qemu
    

    — 如果希望连带调试支持,可使用:

    make qemu-gdb
    riscv64-unknown-elf-gdb
    

构建完成后你将看到 xv6 kernel is booting、多个 hart 启动日志,并进入类似 init: starting sh 的 shell 界面,支持基本 UNIX 命令(如 ls, echo, cat 等)([pdos.csail.mit.edu][1])


二、xv6‑RISC‑V 与原始 Unix V6 的相似与创新

  • 相似点:继承了 Unix V6 的系统调用接口和设计风格(进程调度、fork, exec, pipe, open, read/write 等)([pdos.csail.mit.edu][1])

  • 不同点:现代化实现(ANSI C + RISC‑V),支持 copy-on-write、日志文件系统、多核处理、页面映射、虚拟内存等概念;

    • fork 的实现由 Unix V6 的整块复制变为 按需复制(COW)
    • 文件系统设计加入了 logging 和 crash recovery;
    • 多核支持由原本 XX Uni-core PDP‑11 → RISC‑V 多核 SoC。

三、为什么选择 xv6‑RISC‑V?

  • x86 分支(xv6-public)已于 2018 年停止更新,而 RISC‑V 分支从 2019 年起持续维护,更适合现代教学用途;
  • RISC‑V 是开源 ISA,让你无需购买特定硬件,就能在任何 Linux/macOS 上模拟和调试 xv6;
  • 学术资源丰富:MIT 官方发布教材(book-riscv-rev3.pdf),并提供配套实验题与 GitHub 教学仓库 ([pdos.csail.mit.edu][1])

四、如何深入学习与实验

  1. 阅读教材

    • xv6 book for RISC‑V(可从 MIT 教材或 GitHub 下载)覆盖系统调用、内存管理、中断机制、文件系统与调度算法;
  2. 阅读关键模块代码

    • kernel/trap.c, proc.c, vm.c, fs.c, syscall.c, swtch.S 等源码 README 有模块简介;
  3. 逐章修改并执行实验

    • 可以仿照 MIT 课程的模块自行修改 / 添加实验,例如修改 fork 为多页 COW、加入线程机制、扩展 shell;
  4. 逐步测试与调试

    • 使用 make CPUS=1 qemu-gdb 或在 shell 内加断点,结合 riscv64-unknown-elf-gdb 调试机制。

五、常见问题提示 🔍

问题解决方案
make qemu 显示 “command not found”检查 $PATH 是否包含 riscv‑gnu‑toolchain 的 bin 目录;确认 qemu-system-riscv64 已安装并在 PATH 中
构建 riscv‑toolchain 时间很久(数小时)硬件较慢或并行编译时平均时间较长,可使用 --prefix 更改安装位置,或换用预编译版本
GDB 上提示关于 qemu 连接失败尝试 make qemu-gdb CPUS=1,并确认防火墙未阻止 localhost:26000
使用 macOS 的用户提示 Case‑insensitive filesystem 错误建议使用 HFS+(区分大小写)或在外接设备上创建 case‑sensitive 分区 ([pdos.csail.mit.edu][1])

六、回顾与建议

  • xv6‑RISC‑V 不是为了性能或完整性设计,而是为了教育目的:代码量小(不过仍包含操作系统的主要概念与结构),易于阅读和扩展;
  • 它精炼体现了 UNIX 的“简单规范 + 可组合性”哲学(如系统调用、管道、环回 shell),同时引入现代操作系统技术;
  • 适合初学者、新手系统工程师,以及操作系统课程的作业与实验平台。

https://pdos.csail.mit.edu/6.S081/2023/xv6/book-riscv-rev3.pdf?utm_source=chatgpt.com “xv6: a simple, Unix-like teaching operating system”

http://www.xdnf.cn/news/1234153.html

相关文章:

  • K8S服务发现原理及开发框架的配合
  • 利用AI渲染技术提升元宇宙用户体验的技术难点有哪些?
  • 语义分割--deeplabV3+
  • Navicat连接远程服务器上的mysql
  • ubuntu24.04安装selenium、chrome、chromedriver
  • elk快速部署、集成、调优
  • [Oracle] TO_DATE()函数
  • 二叉树算法之【前序遍历】
  • GitOps:云原生时代的革命性基础设施管理范式
  • 每日五个pyecharts可视化图表-bars(2)
  • Python Seaborn【数据可视化库】 全面讲解
  • 基于图像识别与分类的中国蛇类识别系统
  • k8s日志收集
  • zookeeper常见命令和常见应用
  • SpringBoot学习总结
  • python学智能算法(三十一)|SVM-Slater条件理解
  • Vim编辑器详解:从入门到高效使用
  • 【Unity】背包系统 + 物品管理窗口 (上)
  • 【一天一个知识点】RAG遇见推理
  • 谷歌开源Agent框架ADK快速入门
  • 前端应用权限设计面面观
  • 防御综合实验
  • 【0基础PS】PS工具详解--图案图章工具
  • 安灯系统(Andon System)
  • 【昇腾推理PaddleOCR】生产级部署方式
  • SpringBoot与TurboGears2跨栈、整合AI服务、智能客服路由系统整合实战
  • FreeRTOS源码分析二:task启动(RISCV架构)
  • 单位长度上的RC参数
  • Codeforces Round 1039 (Div. 2) A-C
  • sifu mod制作 相关经验