当按下电脑电源键,一场底层系统的启动接力赛正式开始。首先,主板向电源发出信号唤醒CPU,CPU寄存器被重置初始化,BIOS或UEFI固件率先运行——它像硬件管家一样,逐一检查CPU、内存、硬盘、显卡等设备是否正常,完成后按照预设启动顺序寻找可引导设备(比如硬盘的主引导记录MBR或GPT分区),并将控制权交给引导程序。
引导程序是连接硬件与内核的关键桥梁。常见的GRUB2会读取/boot/grub/grub.cfg配置文件,找到内核镜像(vmlinuz)和临时内存文件系统initrd的路径;而更轻量的systemd-boot则从/boot/loader/entries/加载.conf启动项,先把initrd加载到内存(后续内核会解压它作为临时根文件系统),再通过UEFI函数加载内核镜像,传递启动参数(比如root=/dev/sda1指定根设备)。
此时CPU还处于实模式(16位),寻址空间仅1MB,无法支持现代系统的大内存需求。引导程序会通过lgdt指令加载全局描述符表,将CPU切换到保护模式(32位)或长模式(64位)——保护模式支持内存保护和多任务,长模式则为64位系统提供更大的寻址空间。
切换完成后,内核启动的汇编阶段开始:先检测处理器和机器类型,建立一级页表(比如将RAM基地址映射到0xC0000000虚拟地址),复制数据段、清除bss段,最终调用start_kernel函数进入C语言世界。
start_kernel是内核初始化的核心:首先为0号idle进程(空闲进程)建立内核态堆栈——这是进程运行的基础,存储临时数据和函数返回地址;接着清零eflags寄存器(清除实模式残留的状态标志);然后调用setup_idt填充中断描述符表,为时钟、键盘、页错误等中断注册处理程序。
完成这些后,内核开启中断,正式进入“可运行”状态,随后创建系统的三个核心进程:0号idle进程负责CPU空闲时运行,1号init进程(或systemd)作为用户态第一个进程启动所有用户服务,2号kthreadd进程管理内核线程(比如内存回收、进程调度)。
initrd的作用不可忽视:它是内核启动时的临时根文件系统,里面的init程序会先挂载真正的根文件系统(通常在硬盘上),再将控制权转交给真正的init程序(比如systemd)。
systemd作为现代系统的 init 工具,会并行启动网络、图形界面、登录管理器等服务,最终进入登录阶段——控制台模式用getty提供tty登录,图形模式则通过GDM或LightDM进入桌面。

而内核态与用户态的切换,本质是CPU特权级的变化:内核态是ring0(段选择子尾两位为0),拥有最高权限;用户态是ring3(尾两位为11),受内存保护限制。
通过特定指令执行后,段寄存器的特权级改变,系统从内核态进入用户态,完成从底层内核到用户应用的过渡。
如果用单步调试内核,能清晰看到这一过程:在start函数下断点,看着代码从汇编过渡到C;通过调试工具可视化CPU模式切换——real mode16(实模式)、protected mode32(保护模式)、compatibility mode(兼容32位程序的64位模式)、long mode(64位长模式)依次出现;页表映射也能直观看到,前64兆虚拟内存直接对应物理内存,后续复杂映射则基于此扩展。
从电源启动到用户登录,每一步都像是系统的“底层舞蹈”:BIOS/UEFI搭好舞台,引导程序接棒传递,CPU切换模式解锁能力,内核初始化构建核心,initrd衔接过渡,最终systemd启动所有服务。
这一套流程,正是Linux系统从“硬件通电”到“用户可用”的完整底层逻辑。