x86平台加电后执行的第一行代码,其物理地址位于0xFFFFFFF0,这个地址也被称为复位向量(Reset Vector)。
第一条指令的寻址奥秘
这里有个很巧妙的设计。在刚上电时,CPU处于实模式,这个模式下理论上只能访问1MB的内存空间。但0xFFFFFFF0这个地址远大于1MB,它是如何工作的呢?
关键在于CPU内部代码段(CS)寄存器的初始值被特殊处理了。
特殊的初始状态:上电时,CPU的指令指针(EIP)寄存器被设为
0x0000FFF0,而代码段(CS)的“基址”部分被硬件强制设为0xFFFF0000,而不是常规的0x000F0000。地址合成:第一条指令的物理地址由
CS基址 + EIP合成,即0xFFFF0000 + 0x0000FFF0 = 0xFFFFFFF0。硬件映射:这个特殊的物理地址,在硬件层面会被主板映射到存放BIOS/UEFI固件的ROM芯片(或SPI Flash)上,因此CPU可以在这里取到第一条指令。
这条指令长什么样?
0xFFFFFFF0处存放的并非复杂的操作系统代码,通常是一条跳转(Jump)指令,它的作用是“接力”,将执行流引导到BIOS/UEFI固件代码真正开始的地方。
例如,在开源的UEFI参考实现(EDK2)中,这里的代码简单到只有两条NOP(空操作)指令和一条JMP跳转指令:
; 位于地址 0xFFFFFFF0 nop ; 第一条指令 nop ; 第二条指令 jmp ... ; 跳转到真正的BIOS启动代码
后续启动流程简述
执行完这第一条跳转后,CPU就正式进入了固件的世界,之后会经历一个类似“接力赛”的过程:
BIOS/UEFI固件:进行上电自检(POST)并初始化硬件。
主引导记录(MBR):固件将启动设备的第一个扇区(512字节)加载到内存地址
0x7C00并跳转执行。Bootloader:MBR中的代码(如GRUB stage1)会加载更完整的Bootloader,再由后者将Linux内核加载到内存地址
0x100000。Linux内核:内核接手后,开始执行其自身的初始化代码(入口在
arch/x86/kernel/head_32.S等文件中),最终将控制权移交给操作系统。
所以,0xFFFFFFF0是x86系统上电后一个至关重要的物理坐标,它连接了硬件电路和复杂的软件世界。这个过程非常巧妙,用一段小小的代码,就完成了从硬件到固件再到操作系统的跨越。
x86平台开机执行的第一行代码,位于主板固件(BIOS/UEFI)的ROM或Flash芯片中。因此,它并不属于Linux内核源码的一部分,而是由固件厂商(如Intel、AMI等)提供的代码。