和固件代码不同,Linux内核执行的“第一行”代码位置比较特殊。它不是一个固定的点,而是取决于内核是如何被引导启动的。
最常见的是通过引导程序(如GRUB)加载,此时代码执行会经历两个主要阶段:解压阶段和内核阶段。
内核启动的两种常见路径
传统引导方式 (via Bootloader)
这是最常见的方式,内核镜像(bzImage)包含了被压缩的内核。引导程序加载后,会首先跳转到解压程序,由它负责将内核解压到正确位置,然后再跳转到真正的内核入口。第一行代码 (解压阶段):位于
arch/x86/boot/compressed/head_32.S或head_64.S中的startup_32或startup_64。它负责初始化基本环境,为解压内核做准备。第一行代码 (内核阶段):解压完成后,控制权会移交给真正内核的入口点,位于
arch/x86/kernel/head_32.S或head_64.S。64位下的最终入口函数是startup_64。它开始设置页表等核心工作,并最终跳转到C语言编写的通用初始化函数start_kernel。
UEFI 直接启动方式 (via EFI Stub)
内核也支持被UEFI固件直接启动,就像一个独立的UEFI应用程序。这时,内核镜像里会包含一个EFI兼容的入口点。第一行代码:位于
efi_pe_entry函数中。这个函数遵循UEFI规范,由固件直接调用,初始化完成后,它会再将控制权转交给内核自身的入口点(如上文的内核阶段)。
所以,如果必须选一个最普遍的“第一行”,在x86平台最常见的情况下,它是arch/x86/boot/compressed/head_*.S中的startup_32或startup_64。
这些入口点文件中的汇编代码,就是Linux内核从固件或引导程序手中接过CPU控制权后,执行的第一批指令。