PC机启动后如何执行第一条指令?

时间:2024-03-19 11:51:21

       在过去的三个月内,本人根据《linux内核设计的艺术》和《linux0.11内核完全注释》细读了linux-0.11源码中的大部分内容,最近开始研究清华大学的操作系统实验课中的ucore源代码,因此希望将自己的所思所想分享给大家,也欢迎大家一起来交流探讨。

       当我们按下开机按钮时,电脑是怎么开始执行第一条指令的?

       ①梦回40年前,当时的intel公司生产了一个16位的微处理器芯片8086,它是x86体系架构的鼻祖。但是,8086设计时为了满足当时的寻址要求1MB(个人认为可能当时的内存条最大为1MB),它的地址总线为20位,最大可寻址1MB空间,而数据总线为16位,寄存器也只能存16位的数据,为了填补这4位的差距,intel工程师想出了一个好的方法。一个寄存器存不下,那我用两个寄存器不就行了吗?当时他们的想法是将地址空间分段,因此段寄存器(CS、SS、DS、ES)应运而生,这些寄存器存的是段的基址,我们都知道CPU执行指令是通过CS:IP来执行的,但在当时CS和IP都是16位的,所以intel规定CS:IP=CS<<4+IP,来满足20位寻址。

       背景大概就是这么多了,当时intel公司规定在开机启动后,CPU运行在实模式,根据CS:IP来执行指令,那时候通过硬件逻辑已经将CS写死为0xF000,IP写死为0xFFF0,也就是说只要你开机或断电重启,CPU就会执行0xF000:0xFFF0这个地址里面的指令。按照intel规定,CS:IP=0xFFFF0存放了一条指令”jmp F000:E05B”,按照那么这条指令位于哪个存储设备里面呢?是不是最常见的内存呢?

       ②在8086生产大约7年后,intel新一代32位的微处理器芯片80386开始问世。此时地址总线和数据总线都是32位,为了向下兼容,体系一脉传承,EIP为32为,而其CS、SS、DE、ES仍然设置为16位(程序员可见部分),此时段寄存器存放的都是段选择子,段基址和限长等信息都存储在影子寄存器中(程序员不可见部分),这时通过硬件逻辑将CS写死为0xF000,EIP写死为0x0000FFF0,CS的影子寄存器(存放段基址)写死为0xFFFF0000,CPU按照段基址:偏移的执行方式来执行指令,因此intel工程师在0xFFFF0000+0x0000FFF0的地址处存放了一条指令”jmp F000:E05B”,这条指令执行完后,根据IA32中实模式下跳转指令的说明,CS会被设置为0xF000,EIP被设置为0x0000E05B,而实模式下段基地址计算公式CS base address=CS segment selector * 16=0x000F0000(存放在影子寄存器中),段基址:偏移=0x000F0000+0x0000E05B=0x000FE05B,和8086执行代码移一致。

      “Jmp F000:E05B”存放在哪个存储设备里面?------------>地址空间映射

       80386的地址空间映射:

                                 PC机启动后如何执行第一条指令?

 

       根据上图,我们可以看到0xFFFFFFF0中的地址和0xFE05B的地址都映射到BIOS的地址空间中,所以开机启动后的第一条指令位于BIOS中,首先执行BIOS代码,而不是操作系统的代码,现在的BIOS功能比较完全,在windows系统开机时,你是不是按过F1类似的键进入BIOS系统界面?

       总而言之,CPU访问的是物理地址空间中的地址(位于其地址总线上),然后该地址映射到外部设备上的地址空间(内存、显卡、BIOS等),取出该地址下的指令送回CPU执行。

       IA32中关于第一条指令的说明:

                                  PC机启动后如何执行第一条指令?

 

      参考:

  1. https://www.cnblogs.com/wudibuzaijia/p/8512712.html
  2. https://chyyuu.gitbooks.io/ucore_os_docs/content/lab1/lab1_3_1_bios_booting.html
  3.  IA-32手册
  4. 《Linux内核设计的艺术》
  5. 《linux0.11内核完全注释》