硬核How-to-Make-a-Computer-Operating-System:实模式到保护模式

硬核How-to-Make-a-Computer-Operating-System:实模式到保护模式

【免费下载链接】How-to-Make-a-Computer-Operating-System How to Make a Computer Operating System in C++ 【免费下载链接】How-to-Make-a-Computer-Operating-System 项目地址: https://gitcode.com/gh_mirrors/ho/How-to-Make-a-Computer-Operating-System

你是否曾好奇操作系统如何从开机自检到加载内核?本文将带你深入探索x86架构下操作系统启动的关键转折——从实模式到保护模式的跃迁。通过How-to-Make-a-Computer-Operating-System项目的实战代码,你将掌握GDT(全局描述符表)配置、内存保护机制等核心概念,理解操作系统如何突破1MB内存限制,为后续虚拟内存和多任务打下基础。

实模式:x86架构的"遗产模式"

当x86计算机通电启动时,CPU首先进入实模式(Real Mode)——这是1981年Intel 8086处理器的原始工作模式,为保持兼容性沿用至今。在实模式下:

  • 内存寻址空间仅1MB(20位地址总线)
  • 不支持内存保护和特权级
  • 只能运行16位代码
  • 通过段寄存器:偏移量方式寻址(物理地址=段寄存器值×16+偏移量)

项目中Chapter-1/README.md详细介绍了x86架构背景,指出实模式是"为维持向后兼容性的默认状态"。这种模式下,BIOS完成自检后会将启动设备的第一个扇区(512字节)加载到物理内存0x7C00处,并跳转执行——这就是引导程序的起点。

保护模式:突破1MB限制的关键

实模式的1MB内存限制和缺乏安全机制严重制约现代操作系统发展。保护模式(Protected Mode) 作为x86架构的"成年模式",带来三大突破:

  • 32位地址总线:支持4GB物理内存
  • 内存分段保护:通过段描述符控制访问权限
  • 特权级机制:实现内核态与用户态隔离

项目采用GRUB引导程序自动完成实模式到保护模式的切换。如Chapter-3/README.md所述,GRUB遵循Multiboot规范,能直接加载32位内核并传递硬件信息(通过multiboot_info结构体)。但GRUB提供的临时GDT并不适合我们的内核,需要重新配置自定义GDT。

GDT:保护模式的"交通信号灯"

全局描述符表(GDT) 是保护模式的核心数据结构,定义了内存段的基地址、大小和访问权限。项目中Chapter-6/README.md详细阐述了GDT的实现,其代码位于src/kernel/arch/x86/x86.cc

GDT结构解析

GDT由GDTR(GDT寄存器)段描述符数组组成:

  • GDTR存储GDT的基地址和长度
  • 每个段描述符占8字节,定义一个内存段属性

GDTR结构

GDTR的C语言定义:

struct gdtr {
    u16 limite;  // GDT表长度
    u32 base;    // GDT表基地址
} __attribute__ ((packed));  // 禁止编译器字节对齐

单个段描述符结构如下,包含段基地址、限长和访问控制位:

GDT段描述符

其C语言定义:

struct gdtdesc {
    u16 lim0_15;      // 段限长0-15位
    u16 base0_15;     // 段基地址0-15位
    u8 base16_23;     // 段基地址16-23位
    u8 acces;         // 访问权限字节
    u8 lim16_19:4;    // 段限长16-19位
    u8 other:4;       // 其他标志
    u8 base24_31;     // 段基地址24-31位
} __attribute__ ((packed));

内核自定义GDT配置

项目内核定义了6个关键段描述符,区分内核态与用户态:

段类型选择子权限字节用途说明
内核代码段0x080x9B存放内核可执行代码
内核数据段0x100x93内核数据读写
内核栈段0x180x97内核调用栈
用户代码段0x200xFF用户程序代码(特权级3)
用户数据段0x280xF3用户程序数据
用户栈段0x300xF7用户程序栈

初始化代码位于src/kernel/arch/x86/x86.cc的init_gdt函数:

// 初始化段描述符
init_gdt_desc(0x0, 0xFFFFF, 0x9B, 0x0D, &kgdt[1]);  // 内核代码段
init_gdt_desc(0x0, 0xFFFFF, 0x93, 0x0D, &kgdt[2]);  // 内核数据段
init_gdt_desc(0x0, 0x0, 0x97, 0x0D, &kgdt[3]);      // 内核栈段
// 用户段定义...

// 加载GDT
asm("lgdtl (kgdtr)");

// 更新段寄存器
asm("movw $0x10, %ax\n"    // 数据段选择子
    "movw %ax, %ds\n"
    "movw %ax, %es\n"
    "movw %ax, %fs\n"
    "movw %ax, %gs\n"
    "ljmp $0x08, $next\n"  // 远跳转更新CS寄存器
    "next:");

从实模式到保护模式的切换流程

结合项目代码,完整切换流程如下:

  1. BIOS自检:执行POST(加电自检),初始化硬件
  2. GRUB引导:BIOS加载GRUB到0x7C00,GRUB完成:
    • 切换到保护模式
    • 启用A20地址线(突破1MB限制)
    • 加载内核ELF文件到内存
  3. 内核初始化
  4. 进入内核主函数:调用kmain()开始执行内核逻辑

项目Makefile(src/Makefile)通过以下命令编译内核:

# 编译32位内核,禁用标准库
g++ -m32 -fno-builtin -fno-exceptions -fno-rtti -nostdlib ...

实践验证:如何测试模式切换

项目提供完整的测试环境,通过Vagrant快速搭建开发环境:

  1. 克隆仓库
git clone https://gitcode.com/gh_mirrors/ho/How-to-Make-a-Computer-Operating-System
  1. 启动开发环境
cd src
vagrant up       # 启动虚拟机
vagrant ssh      # 进入开发环境
cd /vagrant
  1. 编译并运行
make all         # 编译内核和用户程序
make run         # 用QEMU启动操作系统

成功启动后,QEMU窗口将显示内核初始化信息,其中GDT配置日志由src/kernel/arch/x86/x86.cc的init_gdt函数输出。

总结与后续挑战

实模式到保护模式的切换是操作系统启动的关键一跃。通过How-to-Make-a-Computer-Operating-System项目的实战代码,我们掌握了:

  • x86架构的两种工作模式特性
  • GDT的结构与配置方法
  • GRUB引导流程与Multiboot规范

后续章节将在此基础上实现分页机制(Chapter-8)、进程调度和虚拟内存。这些技术共同构建起现代操作系统的内存管理基石。

提示:深入理解GDT可参考Intel官方手册第3卷《System Programming Guide》,项目中src/kernel/arch/x86/architecture.h定义了更多硬件相关结构体。收藏本文,下期我们将解析分页机制如何实现内存虚拟化!

【免费下载链接】How-to-Make-a-Computer-Operating-System How to Make a Computer Operating System in C++ 【免费下载链接】How-to-Make-a-Computer-Operating-System 项目地址: https://gitcode.com/gh_mirrors/ho/How-to-Make-a-Computer-Operating-System

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值