• Linux内核开发基础0--实模式,保护模式,长模式


    实模式

    又称为地址模式,它的实体现在两个方面:

    1. 运行真实的指令,对指令的动作不做区分
    2. 发往内存的地址是真实的,对任何地址都不加限制的发往内存

    实模式下的寄存器

    都是16位的
    按照用途分类:
    在这里插入图片描述

    实模式下如何取指令以及访问数据

    指令与数据不加区分的放在内存中,都是二进制数据
    CS :IP指向的地方被解释为指令
    DS/ES/SS :AX/BX/CX/DX/EX/DI/SI/BP/SP指向的地方被解释为数据
    (其中:SS和SP决定栈段)
    段寄存器左移四位 + 通用寄存器中的值/常数 —>形成地址 由这个地址去访问内存 (内存管理模型)
    在这里插入图片描述
    在这里插入图片描述

    实模式下的中断

    中断是CPU响应外部事件的一种方式

    中断向量表

    存放中断响应(服务)代码所在地址
    每一个条目都由代码段地址和段内偏移组成的
    在这里插入图片描述

    中断号

    中断号是服务函数在中断向量表上的偏移地址

    IDTR寄存器

    CPU中的一个特定的寄存器,保存了中断表地址中断表长度(中断表的范围信息)

    中断如何实现实现

    先保存CS和IP,然后装载需要跳转到的位置上的CS和IP

    第一种情况:硬中断:中断控制器给CPU发送一个电平信号,CPU做出应答,中断控制器接收到应答后将中断号告诉CPU,CPU根据中断号做跳转
    第二种情况:软中断:CPU执行INT指令,根据INT指令后跟随的常数,做跳转。这个常数就是中断号

    中断号(偏移量) + IDTR中的中断表地址 ----> 响应代码段的其中一个条目
    将这个条目的基地址和偏移地址装入CS:IP
    在这里插入图片描述

    保护模式

    应对更高的计算量,更大的内存容量的需求

    实模式下寄存器都是16位的,寻址只能指到2的16次方=65535 也就是最大容量为64KB处
    保护模式下就将寄存器都设为32位的

    解决了内存访问大小的问题,之前的实模式的两个特征 却变为了累赘:

    1. CPU对指令不加区分的执行
    2. 对访问内存的地址不加限制

    保护模式下这两问题也都会被解决

    保护模式的特点

    1. 增加了一些控制寄存器和段寄存器
    2. 扩展通用寄存器的位宽,所有通用寄存器都是32位
    3. 可以单独使用低16位,也可以将低16位分为两个8位寄存器使用
      在这里插入图片描述

    保护模式对两个问题的解决

    解决第一个问题:指令不加区分地执行:
    通过实现CPU特权级来区分哪些指令和哪些资源可以被访问
    解决第二个问题:内存访问不受保护:
    通过实现段描述符,对内存进行保护转化为对段进行保护

    特权级

    特权级分为4级,分别对应着保护模式的四个控制寄存器CR0,CR1,CR2,CR3
    每个特权级可以执行的指令数量不同
    R0可以执行所有命令 从R0到R3递减
    在这里插入图片描述

    段描述符

    保护模式下的段寄存器是16位的,而内存信息是32位的,无法放下,所以要找地方借
    实际段描述符占用64位空间:
    在这里插入图片描述
    多个段描述符在内存中可形成全局段描述符,该表的基地址和长度由CPU和GDTR寄存器指示
    在这里插入图片描述
    以前我们的段寄存器作为基地址 配合上IP或者xS等段寄存器的偏移地址就可以直接访问内存
    现在段寄存器作为 具体段描述符的索引(类似数组索引)
    配合上GDTR里面的信息:包括段全局描述符表的基地址(类似数组0号元素的基地址)
    和 段全局描述符表长度(类似数组长度 防止数组访问越界)
    有这些信息可以找到具体的段描述符,再 根据里面的段信息判断能否合法访问

    保护模式下 更强大的段寄存器 — 段选择子

    在这里插入图片描述
    影子寄存器依靠硬件来工作,程序员不可见
    影子寄存器是为了减少性能损耗而设计
    每次访问内存都要去内存中查表,性能损失太大
    影子寄存器是一个段描述符的高速缓存,64位,存放8字节的段描述符的数据

    段描述符索引就是上面所说的用于定位段描述符的索引

    TI指定是从GDT还是LDT中寻找,一般都是0

    RPL指示了访问者的权限级别 常常是RPL = CPL

    CPL是当前权限级别(Current Privilege Level)
    当前正在执行的代码所在的段的特权级,存在于cs寄存器的低两位 CPL标识了代码能够达到的最高的特权级别

    DPL是描述符权限级别(Descriptor Privilege Level)
    存储在段描述符中,规定访问该段的权限级别,每个段的DPL固定
    进程在访问一个段时,需要进行特权级检查,一般要求 DPL > max{CPL,RPL} , 级别至少要相同才能通过检查

    保护模式平坦模型

    分段模型有很多缺陷 现代操作系统都会使用分页模型
    x86 CPU 并不能直接使用分页模型, 而是要在分段模型的前提下, 根据需要决定是否要开启分页。 因为这是硬件的规定, 程序员是无法改变的。
    可以简化设计, 来使分段成为一种“虚设”, 这就是保护模式的平坦模型

    32位寄存器最多能产生4GB大小的地址
    一个段的长度只能是4GB
    可以将所有段的基地址设为0
    段的长度设为0XFFFFF
    段长度的粒度为4KB
    所有段都指向同一个(0~4GB-1)字节大小的地址空间

    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		//DPL为0  最高权限CPL=0时才能访问
    ;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
    GDTBASE dd GDT_START
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    保护模式下的中断

    实模式下中断:CPU直接通过中断向量表中的值来装载CS:IP寄存器
    保护模式下的中断:不能直接查表跳转,需要进行权限检查,特权级切换
    这样一来中断向量表里面就应该包含更多的信息:进化为中断门了—>
    在这里插入图片描述
    中断门和陷阱门唯一的不同也就是置0的不同,陷阱门不会将IF位置0。

    与上面通过段描述符寻址的机制类似:
    同样的, 保护模式要实现中断, 也必须在内存中有一个中断向量表, 同样是由 IDTR 寄存器指
    向, 只不过中断向量表中的条目变成了中断门描述符
    在这里插入图片描述
    这种情况下的查表需要有几个预先的检查:
    CPU 首先会检查中断号是否大于最后一个中断门描述符,x86 CPU 最大支持256 个中断源( 即中断号: 0~255)
    检查描述符类型( 是否是中断门或者陷阱门)
    检查是否为系统描述符
    检查是不是存在于内存中。

    检查中断门描述符中的段选择子指向的段描述符

    最后做权限检查:

  • 相关阅读:
    配置nginx反向代理,监控https流量
    URV5使用指南
    python+yolov3视频车辆检测代码
    Python 爬虫之lxml和Xpath提取网页数据
    抽象类 +接口
    哪些重生奇迹mu地图适合刷玛雅宝石?
    华为云云耀云服务器L实例评测|云耀云服务器L实例部署HertzBeat实时监控系统
    maven安装及配置(详细版)
    python矩阵可视化
    C语言如何判定循环结束和提前结束?
  • 原文地址:https://blog.csdn.net/weixin_43604927/article/details/126322423