操作系统在启动的时候经历了一个从实模式跳转到保护模式的过程,其中一个显著的变化就是CPU的寻址模式发生了重大改变。CPU是逐条从内存地址中取出指令然后解码译码执行,然后CPU的PC加1进入下一条指令的执行。
在实模式下CPU使用20位地址总线,只能访问2^20即1M的地址空间,但是此时寄存器是16位的,因此需要两个16的寄存器才能组合成20位的地址,实模式下采用的是CS (段寄存器)左移4位再加上IP(指令指针)形成物理地址,地址不加变换后直接放到地址总线上。
保护模式下CPU使用32位地址总线,能访问2^32即4G的地址空间,CS(段寄存器)中存放的不再是段值,而是段选择符,通过段选择符到段表中选择相应的段描述符分离出段基址加上IP的值作为物理地址送到地址总线上。
关于实模式与保护模式的寻址方式具体细节请自行百度。
通过将CPU的cr0寄存器的PE(ProtectEnable)位置1,即从实模式变成保护模式了,指令和地址的格式变成32位的了。
可以看出CPU在两个模式下的寻址方式完全不同,但是内核代码在内存中是连续存放的,并且地址都是事先安排好的,那么在CPU从实模式切换到保护模式的时候,指令流是如何连续执行的?如下面的代码:
0x9000: mov %cr0,%eax;
0x9003: or %eax,1;
0x9005:mov %eax,%cr0;
//当本条指令执行后,系统处于保护模式下,此后下一条指令的寻址模式发生改变,以前以实模式方式寻址的时候,计算到的下一条指令地址会是0x9006,而此时保护模式下的寻址计算方式计算出来的结果还会是0x9006吗?显然不会是,但是事实上,系统又能够继续执行下一条0x9006地址上的指令,那么问题来了,这个连续执行是怎么做到的??
0x9006: mov %ecx,%edx;
本问题的微妙之处在于,每个段寄存器包含一个64位的不可见的部分叫做描述符高速缓冲存储器,实模式下会将CS段寄存器的值左移4位后载入到这个描述符高速缓冲存储器中,保护模式下,CPU会将CS中段选择子所描述的段的基址载入到这个描述符高速缓冲存储器器中。CPU每次取指令的时候使用的地址是这个高速缓冲存储器中的值加上IP合成的,而这个高速缓冲存储器中的值不会改变,直到用一条显示的指令修改了CS段寄存器的值。
从上面可以看出0x9005指令并没有改变CS的值,因此还可以按照实模式下的段基址继续执行。