进入内核前的苦力活

导言


在操作系统的演进历程中,Linux 0.11作为经典版本,其启动过程蕴含着深刻的底层设计哲学。从计算机通电到内核正式接管系统,这一阶段涉及硬件初始化、实模式与保护模式切换、内存重定位等核心环节,每一步都堪称现代操作系统启动流程的缩影。

详情见品读 Linux 0.11 核心代码

一、BIOS 加载阶段:启动流程的初始阶段


1.1 启动区加载:系统引导的关键区域

计算机启动时,BIOS 首先读取硬盘主引导记录(MBR),即硬盘 0 盘 0 道 1 扇区。该扇区大小为 512 字节,包含启动代码及分区表信息。启动代码被加载至内存 0x7c00 地址,扇区末尾的 0x55AA 签名作为有效性验证标识。此验证机制确保 BIOS 仅执行合法的启动代码,从而保障系统启动的安全性与可靠性。

1.2 启动代码执行:系统初始化的开端

位于 0x7c00 的 bootsect.s 代码作为启动流程的初始执行模块,承担系统启动初期的环境准备工作。该模块主要负责基本硬件检测、内存环境初始化等基础功能,为后续系统启动奠定基础。

二、内存数据搬运:系统资源的迁移过程


2.1 第一次搬运:启动代码重定位

bootsect.s 执行后,首要任务是将自身从 0x7c00 地址重定位至 0x90000 地址。此次数据迁移旨在释放初始加载区域,为后续代码加载预留空间,并优化代码执行的内存布局。

2.2 第二次搬运:辅助模块加载

随后,BIOS 将硬盘 2 - 5 扇区的 setup.s 代码加载至内存 0x90200 地址。该模块主要负责获取硬件配置信息、初始化系统参数等任务,进一步完善系统启动环境。

2.3 第三次搬运:核心模块加载

最后,硬盘 6 - 245 扇区的 system 模块被加载至内存 0x10000 地址。该模块包含操作系统内核的核心代码与数据,是系统启动的关键组件。

三、寄存器初始化:系统运行环境配置


3.1 段寄存器设置:内存分段管理

在寄存器初始化过程中,段寄存器配置实现内存分段管理。ds/es/fs/gs 寄存器被设置为 0x10(数据段描述符),cs 寄存器设置为 0x08(代码段描述符),ss:esp 指向 user_stack 数组末端。通过上述配置,系统实现了代码段、数据段及堆栈段的逻辑划分,为程序执行提供内存访问基础。

3.2 特殊寄存器配置:系统运行控制

cr0cr3gdtridtr 等特殊寄存器对系统运行起着关键作用。cr0 寄存器的 PE=1 位开启保护模式,PG=1 位开启分页模式;cr3 寄存器指向页目录表;gdtridtr 寄存器分别指向全局描述符表和中断描述符表。这些配置为系统提供内存管理与中断处理机制支持。

四、保护模式切换:系统运行模式升级


4.1 前期准备:模式切换基础配置

在从实模式向保护模式切换前,系统需完成多项准备工作。通过开启 A20 地址线突破 1MB 内存寻址限制,配置全局描述符表(GDT)和中断描述符表(IDT),为保护模式下的内存访问与中断处理提供支持。

4.2 模式切换操作:运行模式转换

通过执行 mov ax,#0x0001lmsw ax 指令,将 CR0 寄存器的 PE 位置 1,实现从实模式到保护模式的切换。此操作使系统具备更强大的内存管理与安全保护能力。

4.3 地址转换机制:内存访问管理

在保护模式下,地址转换采用分段与分页相结合的机制。逻辑地址首先通过分段机制转换为线性地址,再经分页机制转换为物理地址。该机制通过二级页表实现对物理内存的高效管理与访问。

五、分页机制设置:内存管理优化


5.1 页表结构设计:内存管理框架

分页机制通过页目录表和页表构建内存管理体系。页目录表包含 1024 个条目,每个条目指向一个页表;每个页表同样包含 1024 个条目,每个条目对应 4KB 大小的物理页。这种层级结构实现了对物理内存的高效管理与访问。

5.2 地址映射关系:内存空间映射

在系统初始化阶段,线性地址 0 - 16MB 与物理地址 0 - 16MB 建立直接映射关系。该映射关系为系统启动初期的内存访问提供基础支持,并可根据运行需求动态调整。

5.3 分页机制激活:内存管理启用

通过执行 mov eax,cr0or eax,80000000h 指令,将 CR0 寄存器的 PG 位置 1,正式启用分页机制。此操作使系统能够实现高效的内存分配、回收与访问管理。

六、进入 main 函数:内核初始化开始


6.1 执行权转移:程序控制交接

在进入 main 函数前,通过 push _mainpush L6 指令将 main 函数地址压入堆栈,再通过 ret 指令实现执行权转移。该过程确保系统执行流程顺利过渡到内核初始化阶段。

6.2 内核初始化:系统核心启动

main 函数作为内核初始化的入口,从内存 0 地址开始执行。该函数负责初始化系统关键组件,包括内存管理、进程调度、设备驱动等模块,为操作系统的正常运行提供基础支持。

七、核心数据结构:系统运行基础


7.1 全局描述符表 (GDT):内存访问管理

GDT 定义了代码段、数据段、任务状态段(TSS)、局部描述符表(LDT)等条目。通过段选择子与段描述符的对应关系,GDT 为内存访问提供地址转换依据,确保程序正确执行。

7.2 中断描述符表 (IDT):中断处理管理

IDT 包含 256 个中断处理程序地址。当系统发生中断事件时,通过中断号在 IDT 中查找对应的中断描述符,从而调用相应的中断处理程序,保障系统的稳定运行。

7.3 页表结构:内存映射管理

页表结构通过页目录表和页表实现线性地址到物理地址的转换。该机制不仅提高了内存利用率,还为系统提供内存保护功能,确保内核与用户程序的内存空间安全。

八、内存布局:系统资源分配


计算机启动完成后,内存空间被划分为多个功能区域:代码区(0 - 0x80000)存储 system 模块代码;数据区(0x90000 - 0x90200)存储设备信息;栈区(0x9FF00 附近)用于函数调用与局部变量存储;页表区从 0 地址开始,存放页目录表和页表。这种内存布局设计确保系统资源的合理分配与高效利用。

计算机启动全流程与内核初始化涉及硬件与软件的深度交互,其每个环节均经过严谨设计与实现。深入理解该过程不仅有助于掌握计算机系统底层运行原理,还对系统开发、维护与优化具有重要指导意义。


学习Linux 0.11 思维导图