打卡第十天:05 | CPU工作模式:执行程序的三种模式

(2021年11月17日打卡第十天)



05 | CPU工作模式:执行程序的三种模式

学习本节,了解CPU的三种工作模式。

1、实模式工作原理与实模式中断

实模式又称实地址模式,实,即真实,这个真实分为两个方面,一个方面是运行真实的指令,对指令的动作不作区分,直接执行指令的真实功能,另一方面是发往内存的地址是真实的,对任何地址不加限制地发往内存。
在这里插入图片描述

  • 结合上图可以发现,所有的内存地址都是由段寄存器左移 4 位,再加上一个通用寄存器中的值或者常数形成地址,然后由这个地址去访问内存。这就是大名鼎鼎的分段内存管理模型。
  • 代码段是由 CS 和 IP 确定的,而栈段是由 SS 和 SP 段确定的。
data SEGMENT ;定义一个数据段存放Hello World!
    hello  DB 'Hello World!$' ;注意要以$结束
data ENDS
code SEGMENT ;定义一个代码段存放程序指令
    ASSUME CS:CODE,DS:DATA ;告诉汇编程序,DS指向数据段,CS指向代码段
start:
    MOV AX,data  ;data段首地址赋值给AX                
    MOV DS,AX    ;将AX赋值给DS,使DS指向data段
    LEA DX,hello ;使DX指向hello首地址
    MOV AH,09h   ;给AH设置参数09H,AH是AX高8位,AL是AX低8位,其它类似
    INT 21h      ;执行DOS中断输出DX指向的字符串hello
    MOV AX,4C00h ;给AX设置参数4C00h
    INT 21h      ;调用4C00h号功能,结束程序
code ENDS
END start
  • 上述代码中的结构模型,也是符合 CPU 实模式下分段内存管理模式的,它们被汇编器转换成二进制数据后,也是以段的形式存在的。

  • 中断即中止执行当前程序,转而跳转到另一个特定的地址上,去运行特定的代码。
    在实模式下它的实现过程是先保存 CS 和 IP 寄存器,然后装载新的 CS 和 IP 寄存器。

  • 中断分为硬件中断和软件中断。

2、保护模式工作原理、特权级

  • 解决寻址问题:16 位的寄存器最多只能表示 2 16 2^{16} 216个地址(也就是64KB),所以 CPU 的寄存器和运算单元都要扩展成 32 位的($2^{32}$也就是4GB)
  • 解决指令保护问题:CPU 实现了特权级,特权级分为 4 级,R0~R3,每个特权级执行指令的数量不同。
  • 解决内存保护问题:段机制和页机制。
    在这里插入图片描述
  • 我们一眼就可以看出,段寄存器中不再存放段基地址,而是具体段描述符的索引,访问一个内存地址时,段寄存器中的索引首先会结合 GDTR 寄存器找到内存中的段描述符,再根据其中的段信息判断能不能访问成功。
    在这里插入图片描述
  • CS、DS、ES、SS、FS、GS 这些段寄存器,它们是由影子寄存器、段描述符索引(占13位)、描述符表索引TI、权限级别RPL组成的。
  • 通常情况下,CS 和 SS 中 RPL 就组成了 CPL(当前权限级别),所以常常是 RPL=CPL,进而 CPL 就表示发起访问者要以什么权限去访问目标段,当 CPL 在数值上大于目标段 DPL 时(例如CPL=3,DPL=0),则 CPU 禁止访问,只有 CPL 在数值上小于等于目标段 DPL 时才能访问(例如CPL=0,DPL=0或者3)。
  • 我们可以简化设计,来使分段成为一种“虚设”,这就是保护模式的平坦模型。我们把所有段的基地址设为 0,段的长度设为 0xFFFFF1($2^{20}$=1MB,段长度的粒度=4KB,所以一个段的长度为1MB*4KB=4GB),段长度的粒度设为 4KB,这样所有的段都指向同一个(0~4GB-1)字节大小的地址空间。

下面我们还是看一看前面 Hello OS 中段描述符表,如下所示。

GDT_START:
knull_dsc: dq 0
;第一个段描述符CPU硬件规定必须为0
kcode_dsc: dq 0x00cf9e000000ffff
;段基地址=0,段长度=0xfffff
;G=1,D/B=1,L=0,AVL=0 
;P=1,DPL=0,S=1
;T=1,C=1,R=1,A=0
kdata_dsc: dq 0x00cf92000000ffff
;段基地址=0,段长度=0xfffff
;G=1,D/B=1,L=0,AVL=0 
;P=1,DPL=0,S=1
;T=0,C=0,R=1,A=0
GDT_END:

GDT_PTR:
GDTLEN  dw GDT_END-GDT_START-1
;1行和第5行之间有3个段描述符,5-1=4,所以再减1就等于3,也就是这3个段描述符
GDTBASE  dd GDT_START

上面代码中注释已经很明白了,段长度需要和 G 位配合,若 G 位为 1 则段长度等于 0xfffff 个 4KB。上面段描述符的 DPL=0,这说明需要最高权限即 CPL=0 才能访问。

3、长模式工作原理、长模式切换

  • 长模式又名 AMD64,在长模式下,CPU 不再对段基址和段长度进行检查,只对 DPL 进行相关的检查,这个检查流程和保护模式下一样。
  • 下面我们来写一个长模式下的段描述符表,加深一下理解,如下所示:
ex64_GDT:
null_dsc:  dq 0
;第一个段描述符CPU硬件规定必须为0
c64_dsc:dq 0x0020980000000000  ;64位代码段
;无效位填0
;D/B=0,L=1,AVL=0 
;P=1,DPL=0,S=1
;T=1,C=0,R=0,A=0
d64_dsc:dq 0x0000920000000000  ;64位数据段
;无效位填0
;P=1,DPL=0,S=1
;T=0,C/E=0,R/W=1,A=0
eGdtLen   equ $ - null_dsc  ;GDT长度
eGdtPtr:dw eGdtLen - 1  ;GDT界限
     dq ex64_GDT

上面代码中注释已经很清楚了,段长度和段基址都是无效的填充为 0,CPU 不做检查。但是上面段描述符的 DPL=0,这说明需要最高权限即 CPL=0 才能访问。若是数据段的话,G、D/B、L 位都是无效的。
我们既可以从实模式直接切换到长模式,也可以从保护模式切换长模式。切换到长模式的步骤如下。

  1. 准备长模式全局段描述符表:
ex64_GDT:
null_dsc:  dq 0
;第一个段描述符CPU硬件规定必须为0
c64_dsc:dq 0x0020980000000000  ;64位代码段
d64_dsc:dq 0x0000920000000000  ;64位数据段
eGdtLen   equ $ - null_dsc  ;GDT长度
eGdtPtr:dw eGdtLen - 1  ;GDT界限
     dq ex64_GDT
  1. 准备长模式下的 MMU 页表:
mov eax, cr4
bts eax, 5   ;CR4.PAE = 1
mov cr4, eax ;开启 PAE
mov eax, PAGE_TLB_BADR ;页表物理地址
mov cr3, eax
  1. 加载 GDTR 寄存器,使之指向全局段描述表:
lgdt [eGdtPtr]
  1. 开启长模式,要同时开启保护模式和分页模式:
;开启 64位长模式
mov ecx, IA32_EFER
rdmsr
bts eax, 8  ;IA32_EFER.LME =1
wrmsr
;开启 保护模式和分页模式
mov eax, cr0
bts eax, 0    ;CR0.PE =1
bts eax, 31   ;CR0.PG =1
mov cr0, eax 
  1. 进行跳转,加载 CS 段寄存器,刷新其影子寄存器。
jmp 08:entry64 ;entry64为程序标号即64位偏移地址

上述BTS指令的作用:

//两件事::
    判断ecx的值:
        IF ecx == 0CF = 1
        IF ecx != 0CF = 0:
    lock bts dword ptr [ecx],0 //将dword ptr [ecx]指向的内存地址的第0位置1
    
    lock bts dword ptr [ecx],1 //将dword ptr [ecx]指向的内存地址的第1位置1
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值