按下开关后,你的电脑发生了什么

从宏观上来说,你的电脑(其实是你的cpu)将会经历以下三个阶段:

实模式保护模式IA-32e模式(长模式)

其中的IA-32e模式也就是我们最终日常使用时电脑所处于的状态。

不同模式之间的区别是什么?
模式之间的区别主要是寻址方式之间的差别。也就是在不同模式状态下,cpu与内存之间的互动规则不同。并且实模式下最大寻址范围为220Byte=1MB,保护模式下最大寻址范围为232Byte=4GB,IA-32e模式下最大寻址范围为2^64Byte=17179869184GB(理论上)

为什么要经历这三个模式?不能直接就是IA-32e模式吗?
这么做的目的是为了软件兼容性考虑,因为最初的8086cpu只有实模式这一个状态,大家编写的程序自然就运行在保护模式下。等过了一段时间,intel推出了支持保护模式的80286cpu,假如新的cpu直接舍弃了实模式而直接让cpu运行在保护模式下,那么以前大家所写的只能在实模式下运行的软件就无法在这块新的cpu上运行了。所以intel在后续新cpu推出的时候都不会舍弃以前cpu的运行模式,而是设置了几个开关,由用户(操作系统)自行控制cpu的模式。


0.计算机运行的基本原理

0.1 CS:IP

CS:IP?这其实是两个东西。CS(code segment)代码段寄存器,IP(instruction pointer)指令指针寄存器。这两个东西是cpu里的两个结构,cpu通过这两个寄存器,经过一定规则(这个规则在不同的模式下是不同的)的变化转换成地址,然后就运行内存相应地址上的代码。

0.2 内存结构

你可以把内存想象成一连串带有编号的盒子。cpu根据上述的cs:ip找到对应的编号,然后取出盒子里面的代码来执行。


1.实模式

1.1 实模式的寻址方式

通过前面所描述的内容可以得知,不同模式之间主要的区别就在于cpu寻址方式之间的差别。在实模式下,寻址的规则为:

段寄存器 指针寄存器 实际内存地址

上述计算都是16进制下的计算。其中10h为16进制下的10,等价于10进制下的16。

数字前方0x代表着此数为16进制数,或者在数字后方添加h也同样代表16进制。

也就是说,当cs=0x1111, ip=0x1111时,cpu将会运行0x1111*10h+0x1111也就是0x12221处的代码。

1.2 最初的时刻

在接通电源那一刻,cpu就处于实模式中。

以下出自《intel开发人员手册卷3A-part1》

image

也就是说,在开机后最初的时刻,cpu会将运行处于地址0xfffffff0里的代码。也就是我们通常所说的BIOS启动。经过一系列指令后,BIOS启动完成,BIOS将控制权交给用户。

1.3 真正开始接管对电脑的控制

在上述的BIOS启动中,所有的代码都是事先写好在硬件上的,用户并不参与控制。直到BIOS执行结束,用户才开始真正地控制电脑。

在BIOS交出控制权时,此时的cs=0x0000,ip=0x7c00,也就是说,cpu下一句执行的程序位于0x7c00这个地址,并且BIOS会将检查硬盘的第一个扇区中的最后两个字节,如果最后两个字节的数据为0xaa55,则会将第一个扇区内共512字节的数据放置到0x7c00-0x7e00中。在实模式下,最大的寻址空间只有1MB,而如今的内存地址早已普遍在8GB左右,所以电脑并不会在实模式下停留太久时间,而是立刻开始进入保护模式。


2.保护模式

2.1 保护模式下的寻址方式

在保护模式下,寻址方式不同于实模式的段寄存器:指针寄存器,取而代之的是段选择子:偏移地址的寻址方式。此时的cs:ip所寻找的地址就不再是cs10hip。而且仅由cs:ip寄存器在保护模式下是无法寻找到地址的,我们还需要给lgdt寄存器赋予gdt表的基地址以及限长。寻址方式如下图:

image

假设此时cs=0008,ip=00000000,gdt基地址为0x7e00,那么此时的段选择子为cs=0x0008=1000B,则段选择子会在gdt基地址0x7e00上寻找第一个段描述符,此描述符的地址为0x7e08,其中段描述符的结构为:

image

取得段描述符中的段基址后再与偏移地址相加,就可以获得物理地址。

2.2 进入保护模式

从BIOS接管了电脑的控制权后,便会开始着手进入保护模式。

《intel开发人员手册3A-part1》

image

可知,需要进入保护模式,需要准备好以下数据结构:IDT(Interrupt Descriptor Table)中断描述符表GDT(Global Descriptor Table)全局描述符表TSS(task state segment)任务状态段因为只是暂时使用保护模式,一进入保护模式便开始准备进入IA-32e模式,所以不对IDT,TSS进行设置。进入保护模式的示意代码如下:


lgdt [gdt_size]

;====== open A20 address

in al, 0x92

or al, 00000010B

out 0x92, al

;====== open protect mode

mov eax, cr0

or eax, 1

mov cr0, eax

jmp 0x0008:0x00000000

gdt_start_desc  dq  0x0000000000000000

gdt_code_desc  dq  0x00cf9a000000ffff

gdt_data_desc  dq  0x00cf92000000ffff

gdt_size    dw  $ - gdt_start_desc

gdt_base    dd  gdt_start_desc

此时cpu进入保护模式,并且随着一句长转跳jmp 0x0008:0x00000000,cpu开始运行第一个段描述符中的偏移为0处地址的程序,此时运行代码的地址为0x0


3.IA-32e模式

3.1 IA-32e的寻址方式

IA-32e模式的寻址方式,在保留了段选择子的情况下,简化了段描述符的基址与限长,使得段描述符可以直接寻址所有内存空间。并且在开启IA-32e模式的过程中,cpu强制开启页表结构,由对内存的分页来实现对内存的管理。

image

在IA-32e模式中,寻址不仅需要段选择子:偏移地址GDT,还需要页表,通过段选择子:偏移地址GDT形成的地址称为Canonical型地址,经过4重页表转换后就成为了物理地址。页表全局描述符表一样,也是由用户自行设置,基地址由用户操作放入cr3寄存器。

3.2 进入IA-32e模式

《intel开发人员手册3A-part1》

image

可知:

  1. IA-32e模式需要从保护模式中启动,并且需要关闭分页功能

  2. 开启物理地址扩展PAE

  3. 将第四层页表基地址加载至CR3寄存器

  4. 通过将IA32_EFER.LME=1开启IA-32e模式

  5. 开启分页功能。

示意代码如下:


mov dword [0x5000], 0x6007

mov dword [0x6000], 0x7007

mov dword [0x7000], 0x8007

mov dword [0x8000], 0x000

mov    dword [0x8038], 0x7007

lgdt [gdt64_size]

mov eax, cr4

bts eax, 5

mov cr4, eax

mov eax, 0x5000

mov cr3, eax

mov ecx, 0c0000080h

rdmsr

bts eax, 8

wrmsr

mov eax, cr0

bts eax, 31

bts eax, 0

mov cr0, eax

start_desc dq 0x0000000000000000

code_desc  dq 0x0000980000000000

data_desc  dq 0x0000920000000000

gdt64_size dw $-start_desc

gdt64_base dd start_desc

至此,cpu就进入我们日常使用的IA-32e模式了,接下来就是由操作系统来接管电脑的控制。

你可能感兴趣的:(按下开关后,你的电脑发生了什么)