orange's学习--cpu第一条指令理解

版权声明:原创作者:http://blog.csdn.net/port23 。 欢迎讨论转载,请注明来源: https://blog.csdn.net/port23/article/details/86710806

cpu第一条指令理解

计算机cpu自动上电后,寄存器就会设置成初始值,有些书上说CS=0xFFFF IP=0x0000,例如linux内核设计的艺术(第三版)。
也有一些书说CS=F000 IP=FFF0,例如赵炯的linux内核完全注释。
其实并不是说对与错,这个差异的原因本身是由于不同的硬件初始化导致的不同,两种初始化虽然值不同,
但是在实模式下CS:IP最后的值都是0xFFFF0,这个值是硬件自动初始化的。也是上电后cpu执行的第一条执行地址。BIOS也是存储于这段空间。
例如8K的BIOS,本身存储在ROM中,由于影子内存的原因导致上电映射到0xFE000~0xFFFFF中。

而上电硬件自动初始化的CS:IP会自动跳转到这段空间(BIOS空间)。最后的步骤就是BIOS的一些构建,诸如中断向量表、BIOS数据区、BIOS中断服务程序部分的内存映射。

转载: https://www.cnblogs.com/ay-a/p/9058509.html


--另外一种对CPU第一条指令地址的理解(这儿CPU开机默认是保护模式,并且段寄存器有更复杂的设计,问题是BIOS怎么映射过来的?)
https://blog.csdn.net/lightseed/article/details/4735101
当HW reset后,CPU会到(物理地址为)0FFFF FFF0H处去取指令并执行之。这个地址很明显是CPU的最高物理地址往下数16个bytes的地址处。
我想只要是刚入门的freshman都会感到比较疑惑,这个地址(FFFF FFF0H)明明是大于1Mbyte的地址了,而此时的CPU却是在实模式下的,那么CPU是怎么到这里去取指令的呢?
虽然我们是处于实模式,但是由于我们的段寄存器(segment register)是由两个部分组成的,一部分是可见的段选择子,
另外一部分是隐藏部分(段基地址)其实是每个段寄存器增加了段描述符高速缓冲寄存器======等于进入gdt表获取的。

如果我们在protect mode中修改好了段寄存器的段基地址部分,然后返回实模式,那么只要不显示地修改段寄存器,
CPU在寻址的时候仍然会照protect mode下的寻址方式来计算地址,即:segment selector:offset。

如果我们用CS:IP是用F000H:FFF0H的方式来操作的时候,CPU其实是会把地址这样算的。F000H是CS的段选择子,
从这里取出CS的基地址(就是FFFF0000H)再加上IP的值(FFF0H)就等于实际要访问的内存地址(正好是FFFF FFF0H)[FFFF0000+FFF0H=FFFFFFF0H]。
所以在32bit的CPU上,这个第一条指令的计算是这样来的。

不过一般情况下HW reset后,BIOS都会在第一条指令这里安排一个far jump来显示地修改CS的值,
目的就是能够让CS真正进入real mode。就是让CS能够遵从正常的real mode的寻址翻译规则。(CS base address = CS segment selector * 16)。


我们对实模式和保护模式做了比较详细地探讨,说了那么多其实都是为这篇文章服务的。因为在BIOS POST的过程中经常要用到1M以上的内存。
但是BIOS本身的code却又都是在实模式中运行的。当然我们可以进入保护模式去访问内存,然后再切会实模式。如此反复我们是可以做到的,但是这样必定是比较麻烦的。
有没有一种模式,我们在实模式下就可以直接访问到4G的内存呢?答案是肯定的。它的名字就叫做“Big Real Mode”。


在mov cr0,eax执行后,处理器实际上已经处于保护模式。然而,Prefetch Queue值仍为实模式下的值。
(其中最重要的是cs)注意,段寄存器不仅包括16位可见部分,还包括48位高速缓冲(也就是我们programming guide里的,“visible” part and a “hidden” part)。
在进入保护模式后,这些段寄存器高速缓冲中的内容仍然存在,而且CPU为了其执行指令的效率只要CS或者其他的DS等等段寄存器如果没有改变,
那么CPU都直接从这些高速缓冲器中去取CS和DS的值。(但是进入保护模式后,CPU预取的指令却全是实模式下的地址,当然会在保护模式下寻址时出问题。)
那么我们就需要改变CS等等段寄存器的值(不过在保护模式下应该叫做段选择子了)需要显式(就是直接修改CS的意思)地重新加载。
加载其他段寄存器可以mov,但是只有jmp(far ptr)可以加载cs。注意,还有一些转移指令,如retf,iret等,但是这牵扯到保护模式下复杂的远返回操作,
而且需要堆栈(通常这个时候保护模式堆栈还没有淮备好)所以far jmp是最简单有效的办法。
所以最主要的还是要去改变CS的值,从而能够在保护模式下让code正常运行。顺便提示一下,我们著名的the big real mode就是运用了这个原理,
当不去改变相应段选择子的时候,他们各自的hidden部分(高速缓冲部分)是不会被重新加载的。
所以我们进入保护模式后修改好相应段选择子然后返回real mode,直接可以访问4G内存空间。

扫描二维码关注公众号,回复: 5345310 查看本文章

猜你喜欢

转载自blog.csdn.net/port23/article/details/86710806