文章

Pintos Kernel 启动详解(零):系列概述

Pintos 操作系统内核启动代码的详细分析文档系列概述,包括文档列表、阅读顺序和先决知识。

Pintos Kernel 启动详解(零):系列概述

概述

这是一个针对 Pintos 操作系统内核启动代码的详细分析文档系列,力求用简单易懂的方式解释每一个概念和代码片段。

本系列是 Loader 系列的延续——Loader 将内核加载到内存后,跳转到内核的入口点 start(位于 start.S),接着内核开始自己的初始化过程,最终调用 C 语言编写的 pintos_init() 函数。


从 Loader 到 Kernel 的过渡

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
31
┌─────────────────────────────────────────────────────────────────┐
│                        引导过程流程                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   BIOS                                                          │
│     │                                                            │
│     ▼                                                            │
│   loader.S (0x7C00)     ← 实模式 (16-bit)                        │
│     │ 加载内核到 0x20000                                          │
│     │ 跳转到 start                                               │
│     ▼                                                            │
│   start.S (0x20000)     ← 实模式 → 保护模式 (32-bit)              │
│     │ 获取内存大小                                               │
│     │ 启用 A20 地址线                                            │
│     │ 设置临时页表                                               │
│     │ 切换到保护模式                                              │
│     │ 启用分页                                                   │
│     │ 调用 pintos_init()                                         │
│     ▼                                                            │
│   init.c:pintos_init()  ← C 语言内核主函数                        │
│     │ 初始化 BSS 段                                              │
│     │ 解析命令行参数                                              │
│     │ 初始化线程系统                                              │
│     │ 初始化内存系统                                              │
│     │ 初始化中断系统                                              │
│     │ 启动调度器                                                 │
│     │ 执行用户任务                                               │
│     ▼                                                            │
│   正常运行...                                                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

文档列表

本系列包含以下文档:

Part 1: start.S 汇编启动代码

序号主题简介
1start.S 概述与初始段寄存器设置内核入口点和基本环境设置
2内存大小检测使用 BIOS 中断获取物理内存大小
3A20 地址线启用解决历史遗留的 1MB 内存限制
4临时页表创建创建页目录和页表实现虚拟内存映射
5保护模式切换从 16 位实模式切换到 32 位保护模式
6GDT 全局描述符表GDT 的结构和作用详解

Part 2: init.c 内核初始化

序号主题简介
7pintos_init 主函数内核 C 语言入口和初始化流程
8BSS 段初始化清零未初始化的全局变量区域
9命令行解析读取和解析内核启动参数
10内存系统初始化palloc 和 malloc 内存分配器初始化
11永久页表建立替换临时页表建立完整的虚拟内存映射
12线程系统初始化初始化线程调度器和主线程
13中断系统初始化IDT、PIC 和中断处理框架
14设备初始化定时器、键盘、串口等设备初始化
15启动完成与任务执行启动调度器并执行用户指定的任务

阅读顺序

建议按照文档编号顺序阅读,因为:

  1. 文档按执行顺序组织:代码是按顺序执行的,文档也按这个顺序排列
  2. 概念层层递进:后面的文档会引用前面介绍的概念
  3. 从汇编到 C:先理解底层汇编代码,再学习 C 语言初始化

如果你已经阅读过 Loader 系列,可以直接从本系列开始。如果没有,建议先阅读 Loader 系列了解引导过程。


每个文档的结构

每个文档都包含以下部分:

  • 概述:本部分代码的作用和重要性
  • 原始代码:完整的源代码
  • 前置知识:理解代码所需的背景知识
  • 逐行详解:每一行代码的详细解释
  • 图解/流程图:可视化的执行过程和数据结构
  • 常见问题:FAQ 解答常见疑惑
  • 练习思考:帮助加深理解的思考题

先决知识

阅读这些文档前,最好了解:

必须了解

  • Loader 系列文档:了解引导过程和实模式基础
  • C 语言基础:函数、指针、结构体
  • 十六进制:内存地址的表示

基本计算机概念

  • 内存和 CPU 的关系
  • 程序如何执行
  • 堆栈的概念

可选但有帮助

  • x86 汇编语言基础
  • 虚拟内存的基本概念
  • 操作系统原理

核心概念速览

实模式 vs 保护模式

特性实模式保护模式
位宽16 位32 位
最大内存1 MB4 GB
内存保护
多任务支持
地址模型段:偏移线性地址 + 分页

关键内存地址

地址内容
0x7C00Loader 加载位置
0x20000 (128KB)内核加载位置
0xC0000000 (3GB)内核虚拟地址基址
0xF000 (60KB)初始栈顶/临时页目录

关键寄存器

寄存器用途
CR0控制寄存器,包含 PE(保护模式)、PG(分页)位
CR3页目录基址寄存器
GDTR全局描述符表寄存器
IDTR中断描述符表寄存器

术语表

术语解释
GDT全局描述符表,定义内存段
IDT中断描述符表,定义中断处理程序
PDE页目录项
PTE页表项
A20地址线 20,启用后可访问超过 1MB 的内存
BSS未初始化数据段,程序启动时需要清零
PIC可编程中断控制器
TSS任务状态段

相关文件

汇编文件

  • src/threads/start.S - 内核汇编入口点
  • src/threads/intr-stubs.S - 中断桩代码

C 源文件

  • src/threads/init.c - 内核主初始化函数
  • src/threads/thread.c - 线程管理
  • src/threads/interrupt.c - 中断处理
  • src/threads/palloc.c - 页面分配器
  • src/threads/malloc.c - 内核内存分配器

头文件

  • src/threads/loader.h - 引导相关常量
  • src/threads/thread.h - 线程结构定义
  • src/threads/vaddr.h - 虚拟地址操作宏
  • src/threads/pte.h - 页表项操作宏

学习建议

  1. 边读边画:画出内存布局和执行流程图
  2. 对照代码:打开源文件对照阅读
  3. 动手调试:使用 GDB 单步执行,观察寄存器和内存变化
  4. 做笔记:记录自己的理解和疑问
  5. 多问为什么:理解每行代码存在的原因

调试技巧

使用 GDB 调试内核启动

1
2
3
4
5
6
7
8
# 在 Pintos 目录下
pintos --gdb -- run <test>

# 在另一个终端
pintos-gdb kernel.o
(gdb) target remote localhost:1234
(gdb) break start
(gdb) continue

有用的 GDB 命令

# 查看寄存器
info registers

# 查看内存
x/10x 0x20000

# 查看页表
monitor info pg

# 单步执行
stepi

下一步

准备好了吗?让我们开始第一篇文档:start.S 概述与初始段寄存器设置

本文由作者按照 CC BY 4.0 进行授权