第一条指令(ResetVector)
先说结论:X86 CPU启动后,将从地址0xFFFFFFF0处开始执行(此地址并非内存地址。此时,内存还远远没有初始化。)。这一章来看X86系统是如何实现这一点的。
加电或者RESET针脚被激发(Assert)后[ref intel] CPU会经历如下几个过程:
1. CPU首先会进行硬件初始化(hardware reset)。
2. 然后是可选的自检过程(BIST built-in self-test)。
3. CPU开始执行第一条指令。从此开始CPU进入软件初始化过程。
1.CPU硬件初始化
CPU硬件初始化完成后,CPU被设置为实地址模式,地址无分页。所有寄存器被初始化为特定的值, Cache、TLB(Translation Lookup Table)、BLB(Branch Target Buffer)这三个部件的内容被清空(Invalidate)。
2.自检
CPU硬件初始化过程中,硬件可能请求执行自检。如果执行自检,自检完成后,EAX的值为自检错误码,0表示没有任何错误;
3.第一条指令
现在,完事俱备,CPU已经准备好,迫不及待地要执行第一条指令了。且慢,这是一个重要的时刻,此刻决定了CPU能否正常指令,让我们详细了解一下CPU目前的状态。
表1-1 CPU初始化后的寄存器(部分)
Register | Pentium 4 and Intel Xeon Processor | P6 Family Processor Including DisplayFamily = 06H) | Pentium Processor |
---|---|---|---|
EFLAGS1 | 00000002H | 00000002H | 00000002H |
EIP | 0000FFF0H | 0000FFF0H | 0000FFF0H |
CR0 | 60000010H | 60000010H | 60000010H |
CR2, CR3, CR4 | 00000000H | 00000000H | 00000000H |
CS | Selector = F000H Base = FFFF0000H Limit = FFFFH AR = Present, R/W, Accessed | Selector = F000H Base = FFF0000H Limit = FFFFH AR = Present, R/W, Accessed | Selector = F000H Base = FFFF0000H Limit = FFFFH AR = Present, R/W, Accessed |
SS, DS, ES, FS, GS | Selector = 0000H Base = 00000000H Limit = FFFFH AR = Present, R/W, Accessed | Selector = 0000H Base = 00000000H Limit = FFFFH AR = Present, R/W, Accessed | Selector = 0000H Base = 00000000H Limit = FFFFH AR = Present, R/W, Accessed |
EDX | 00000FxxH | 000n06xxH | 000005xxH |
EAX | 0 | 0 | 0 |
EBX, ECX, ESI, EDI, EBP,ESP | 00000000H | 00000000H | 00000000H |
此处我们最关心的是指令执行相关的两个寄存器EIP(Instruction Pointer)、CS(Code Segment)。
在实地址模式下(寄存器字长为16位),指令的物理地址是CS << 4 + EIP。段寄存器CS左移四位作为基址,再加上作为偏移的EIP,最终形成指令的物理地址。现代CPU中为了加速指令地址的计算,为每个段寄存器增加了两个寄存器:Base和Limit。Base存放基址,Limit存放最大偏移值。Base和Limit寄存器不能通过指令直接读写,他们的值是在写段寄存器时由CPU自动设置的。通常Base等于段寄存器左移四位,如果CS的值为0xF000,CS的Base寄存器则为0xF0000,但CPU初始化时例外。从表1-1可以看出CS的值为0xF000, 但其Base为0xFFFF0000,EIP为0xFFF0,此时对应的指令地址为0xFFFF0000+0xFFF0 = 0xFFFFFFF0。0xFFFFFFF0就是CPU将要执行的第一条指令。这造成这样一个有趣的事实,16位程序眼中的指令地址空间0x0000~0xFFFF(大小为64K)被CPU翻译到物理地址空间(0xFFFF0000~0xFFFFFFFF)。也就是说,从CPU初始化,到段寄存器被重写(通过跨段跳转指令)前,指令空间0x0000~0xFFFF通过段寄存器被映射到物理地址空间0xFFFF0000~0xFFFFFFFF。