X86 CPU 工作模式

1.概述

1.实模式

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

指令的操作数,可以是寄存器、内存地址、常数,其实通常情况下是寄存器,AX、CX 就是 x86 CPU 中的寄存器。

下面我们就去看看 x86  CPU 在实模式下的寄存器。表中每个寄存器都是 16 位的。

特别注意段寄存器(CS,DS,ES,SS)分别指代码段寄存器,数据段寄存器,辅助段寄存器,堆栈段寄存器

虽然有了寄存器,但是数据和指令都是存放在内存中的。通常情况下,需要把数据装载进寄存器中才能操作,还要有获取指令的动作,这些都要访问内存才行,而我们知道访问内存靠的是地址值。

上面就是所谓的分段内存管理模型下的取指和内存访问的方法,所有的内存地址都是由段寄存器左移 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中断输出DS指向的DX指向的字符串helloMOV AX,4C00h ;给AX设置参数4C00hINT 21h      ;调用4C00h号功能,结束程序
code ENDS
END start

 LEA 是取地址指令,MOV 是数据传输指令,就是 INT 中断你可能还不太明白,下面我们就来研究它。

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

第一种情况是,中断控制器给 CPU 发送了一个电子信号,CPU 会对这个信号作出应答。随后中断控制器会将中断号发送给 CPU,这是硬件中断。第二种情况就是 CPU 执行了 INT 指令,这个指令后面会跟随一个常数,这个常数即是软中断号。这种情况是软件中断。

为了实现中断,就需要在内存中放一个中断向量表,这个表的地址和长度由 CPU 的特定寄存器 IDTR 指向。实模式下,表中的一个条目由代码段地址和段内偏移组成,如下图所示。

有了中断号以后,CPU 就能根据 IDTR 寄存器中的信息,计算出中断向量中的条目,进而装载 CS(装入代码段基地址)、IP(装入代码段内偏移)寄存器,最终响应中断。

2.保护模式

保护模式相比于实模式,增加了一些控制寄存器和段寄存器,扩展通用寄存器的位宽,所有的通用寄存器都是 32 位的,还可以单独使用低 16 位,这个低 16 位又可以拆分成两个 8 位寄存器,如下表。

为了区分哪些指令(如 in、out、cli)和哪些资源(如寄存器、I/O 端口、内存地址)可以被访问,CPU 实现了特权级。特权级分为 4 级,R0~R3,每个特权级执行指令的数量不同,R0 可以执行所有指令,R1、R2、R3 依次递减,它们只能执行上一级指令数量的子集。而内存的访问则是靠后面所说的段描述符和特权级相互配合去实现的。如下图.

目前为止,内存还是分段模型,要对内存进行保护,就可以转换成对段的保护。

由于 CPU 的扩展导致了 32 位的段基地址和段内偏移,还有一些其它信息,所以 16 位的段寄存器肯定放不下。放不下就要找内存借空间,然后把描述一个段的信息封装成特定格式的段描述符,放在内存中,其格式如下。

一个段描述符有 64 位 8 字节数据,里面包含了段基地址、段长度、段权限、段类型(可以是系统段、代码段、数据段)、段是否可读写,可执行等。虽然数据分布有点乱,这是由于历史原因造成的。

多个段描述符在内存中形成全局段描述符表,该表的基地址和长度由 CPU 的 GDTR 寄存器指示。如下图所示。

段寄存器中不再存放段基地址,而是具体段描述符的索引,访问一个内存地址时,段寄存器中的索引首先会结合 GDTR 寄存器找到内存中的段描述符,再根据其中的段信息判断能不能访问成功。

如果你认为 CS、DS、ES、SS、FS、GS 这些段寄存器,里面存放的就是一个内存段的描述符索引,那你可就草率了,其实它们是由影子寄存器、段描述符索引、描述符表索引、权限级别组成的。如下图所示

影子寄存器是靠硬件来操作的,对系统程序员不可见,是硬件为了减少性能损耗而设计的一个段描述符的高速缓存,不然每次内存访问都要去内存中查表,那性能损失是巨大的,影子寄存器也正好是 64 位,里面存放了 8 字节段描述符数据。

通常情况下,CS 和 SS 中 RPL 就组成了 CPL(当前权限级别),所以常常是 RPL=CPL,进而 CPL 就表示发起访问者要以什么权限去访问目标段,当 CPL 大于目标段 DPL 时,则 CPU 禁止访问,只有 CPL 小于等于目标段 DPL 时才能访问。

3.保护模式中断

实模式下 CPU 不需要做权限检查,所以它可以直接通过中断向量表中的值装载 CS:IP 寄存器就好了。

而保护模式下的中断要权限检查,还有特权级的切换,所以就需要扩展中断向量表的信息,即每个中断用一个中断门描述符来表示,也可以简称为中断门,中断门描述符依然有自己的格式,如下图所示。

同样的,保护模式要实现中断,也必须在内存中有一个中断向量表,同样是由 IDTR 寄存器指向,只不过中断向量表中的条目变成了中断门描述符,如下图所示

产生中断后,CPU 首先会检查中断号是否大于最后一个中断门描述符,x86 CPU 最大支持 256 个中断源(即中断号:0~255),然后检查描述符类型(是否是中断门或者陷阱门)、是否为系统描述符,是不是存在于内存中。

接着,检查中断门描述符中的段选择子指向的段描述符。

保护模式下中断过程: 对于保护模式下的中断,如果中断号在0-255。首先通过IDTR和中断号找到中断门描述符,根据中断门描述符属性部分中的DPL来判断当前权限是否能执行该中断。如果CPL<=DPL,则允许通过段选择子和段偏移访问对应的段。 接着根据段选择子可以在GDTR或LDTR中找到对应段的描述符。访问段首先需要检查段选择子中的DPL,如果CPL=DPL则可以直接访问;如果CPL>DPL则需要切换权限才能进一步访问,例如从用户态切换到内核态,此时会从TSS中加载具体权限的相应栈寄存器,切换栈运行环境后才可以继续访问。所谓访问段就是将对应段的段选择子和段内偏移加载到对应寄存器(CS、EIP),然后按序取址执行即可。执行完后会恢复到原来的权限状态。 上述涉及到保护模式下的权限问题,什么时候能跨权限执行? ① 访问高权限的一致代码段(例如共享的,不访问保护资源的代码);② 通过合法的权限切换手段(例如中断、异常、系统调用等)

4.切换到保护模式

x86 CPU 在第一次加电和每次 reset 后,都会自动进入实模式,要想进入保护模式,就需要程序员写代码实现从实模式切换到保护模式。切换到保护模式的步骤如下。

第一步,准备全局段描述符表,代码如下。

GDT_START:
knull_dsc: dq 0
kcode_dsc: dq 0x00cf9e000000ffff
kdata_dsc: dq 0x00cf92000000ffff
GDT_END:
GDT_PTR:
GDTLEN  dw GDT_END-GDT_START-1
GDTBASE  dd GDT_START

第二步,加载设置 GDTR 寄存器,使之指向全局段描述符表。

lgdt [GDT_PTR]

第三步,设置 CR0 寄存器,开启保护模式。

;开启 PE
mov eax, cr0
bts eax, 0                      ; CR0.PE =1
mov cr0, eax         

第四步,进行长跳转,加载 CS 段寄存器,即段选择子。因为在刚进入保护模式下, 原来的段寄存器信息还残留在,而这些数据在保护模式下是没有用的, 所以需要长跳转来清空指令流水线,使CPU重新加载信息

jmp dword 0x8 :_32bits_mode ;_32bits_mode为32位代码标号即段偏移

接下来,CPU 发现了 CRO 寄存器第 0 位的值是 1,就会按 GDTR 的指示找到全局描述符表,然后根据索引值 8,把新的段描述符信息加载到 CS 影子寄存器,当然这里的前提是进行一系列合法的检查。到此为止,CPU 真正进入了保护模式,CPU 也有了 32 位的处理能力。

5.长模式

长模式又名 AMD64,因为这个标准是 AMD 公司最早定义的,它使 CPU 在现有的基础上有了 64 位的处理能力,既能完成 64 位的数据运算,也能寻址 64 位的地址空间

长模式相比于保护模式,增加了一些通用寄存器,并扩展通用寄存器的位宽,所有的通用寄存器都是 64 位,还可以单独使用低 32 位。这个低 32 位可以拆分成一个低 16 位寄存器,低 16 位又可以拆分成两个 8 位寄存器,如下表。

长模式依然具备保护模式绝大多数特性,如特权级和权限检查。相同的部分就不再重述了,这里只会说明长模式和保护模式下的差异。下面我们来看看长模式下段描述的格式,如下图所示。

在长模式下,CPU 不再对段基址和段长度进行检查,只对 DPL 进行相关的检查,这个检查流程和保护模式下一样。

在长模式(64 位模式)中,x86 架构对段机制进行了根本性简化:

  • 段基地址:所有段寄存器(CS、DS、ES、SS 等)的基地址固定为 0
  • 段界限:所有段的界限固定为最大值(0xFFFFFFFFFFFFFFFF)。
  • 段描述符:仍然存在,但仅用于权限检查(如 CPL、DPL)和内存类型标识(如代码段 / 数据段)。

这种设计使得段机制不再参与地址计算,而是由RIP 寄存器直接提供线性地址,就像平坦模式一样。

在长模式下,RIP 寄存器的值(或内存操作数的有效地址)直接作为 MMU 的输入虚拟地址

下面我们来写一个长模式下的段描述符表,加深一下理解,如下所示.

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

6.长模式中断

保护模式下为了实现对中断进行权限检查,实现了中断门描述符,在中断门描述符中存放了对应的段选择子和其段内偏移,还有 DPL 权限,如果权限检查通过,则用对应的段选择子和其段内偏移装载 CS:EIP 寄存器。如果你还记得中断门描述符,就会发现其中的段内偏移只有 32 位,但是长模式支持 64 位内存寻址,所以要对中断门描述符进行修改和扩展,下面我们就来看看长模式下的中断门描述符的格式,如下图所示。

首先为了支持 64 位寻址中断门描述符在原有基础上增加 8 字节,用于存放目标段偏移的高 32 位值。其次,目标代码段选择子对应的代码段描述符必须是 64 位的代码段。最后其中的 IST 是 64 位 TSS 中的 IST 指针,因为我们不使用这个特性,所以不作详细介绍。

7.切换到长模式

我们既可以从实模式直接切换到长模式,也可以从保护模式切换长模式。切换到长模式的步骤如下。第一步,准备长模式全局段描述符表。

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

第二步,准备长模式下的 MMU 页表,这个是为了开启分页模式,切换到长模式必须要开启分页,想想看,长模式下已经不对段基址和段长度进行检查了,那么内存地址空间就得不到保护了。而长模式下内存地址空间的保护交给了 MMU,MMU 依赖页表对地址进行转换,页表有特定的格式存放在内存中,其地址由 CPU 的 CR3 寄存器指向。

mov eax, cr4
bts eax, 5   ;CR4.PAE = 1
mov cr4, eax ;开启 PAE
mov eax, PAGE_TLB_BADR ;页表物理地址
mov cr3, eax

第三步,加载 GDTR 寄存器,使之指向全局段描述表:

lgdt [eGdtPtr]

第四步,开启长模式,要同时开启保护模式和分页模式,在实现长模式时定义了 MSR 寄存器,需要用专用的指令 rdmsr、wrmsr 进行读写,IA32_EFER 寄存器的地址为 0xC0000080,它的第 8 位决定了是否开启长模式,MSR是CPU的一组64位寄存器,可以分别通过RDMSR和WRMSR 两条指令进行读和写的操作,前提要在ECX中写入MSR的地址。 对于RDMSR 指令,将会返回相应的MSR 中64bit 信息到(EDX:EAX)寄存器中;对于WRMSR 指令,把要写入的信息存入(EDX:EAX)中,执行写指令后,即可将相应的信息存入ECX 指定的MSR 中。MSR 的指令必须执行在level 0 或实模式下。

;开启 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
mov cr0, eax 

第五步,进行跳转,加载 CS 段寄存器,刷新其影子寄存器。

jmp 08:entry64 ;entry64为程序标号即64位偏移地址

切换到长模式和切换保护模式的流程差不多,只是需要准备的段描述符有所区别,还有就是要注意同时开启保护模式和分页模式。原因在上面已经说明了。

参考:LMOS 操作系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/87864.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java设计模式之行为型模式(策略模式)介绍与说明

一、策略模式简介 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以相互替换&#xff0c;且算法的变化不会影响使用算法的客户。策略模式让算法独立于使用它的客…

【BIOS+MBR 微内核手写实现】

本文基于BIOS+MBR的架构,从四部分讲解微内核是如何实现的: 1)搭建微内核编译调试环境 2)梳理微内核的代码结构:伪指令讲解 3)手写实现微内核框架,输出简单的字符串 4)讲解微内核启动阶段的具体运行过程 先完成内核工程创建,如下图 我们这里使用nasm风格的汇编编写,…

从C/C++迁移到Go:内存管理思维转变

一、引言 在当今高速发展的软件开发世界中&#xff0c;语言迁移已成为技术进化的常态。作为一名曾经的C/C开发者&#xff0c;我经历了向Go语言转变的全过程&#xff0c;其中最大的认知挑战来自内存管理模式的根本性差异。 我记得第一次接触Go项目时的困惑&#xff1a;没有析构函…

正确设置 FreeRTOS 与 STM32 的中断优先级

在裸机开发&#xff08;非 RTOS&#xff09;时&#xff0c;大多数 STM32 外设的中断优先级通常不需要手动配置&#xff0c;原因如下&#xff1a; ✅ 裸机开发中默认中断优先级行为 特点说明默认中断优先级为 0如果你不设置&#xff0c;STM32 HAL 默认设置所有外设中断为 0&…

EasyExcel之SheetWriteHandler:解锁Excel写入的高阶玩法

引言在 EasyExcel 强大的功能体系中&#xff0c;SheetWriteHandler 接口是一个关键的组成部分。它允许开发者在写入 Excel 的 Sheet 时进行自定义处理&#xff0c;为实现各种复杂的业务需求提供了强大的支持。通过深入了解和运用 SheetWriteHandler 接口&#xff0c;我们能够更…

Python单例模式魔法方法or属性

1.单例模式概念定义:单例模式(Singleton Pattern)是一种创建型设计模式&#xff0c;它确保一个类只能有一个实例&#xff0c;并提供一个全局访问点来获取该实例。这种模式在需要控制资源访问、配置管理或协调系统操作时特别有用。核心特点:私有构造函数&#xff1a;防止外部通过…

【Kubernetes系列】Kubernetes 资源请求(Requests)

博客目录 引言一、资源请求的基本概念1.1 什么是资源请求1.2 请求与限制的区别 二、CPU 请求的深入解析2.1 CPU 请求的单位与含义2.2 CPU 请求的调度影响2.3 CPU 请求与限制的关系 三、内存请求的深入解析3.1 内存请求的单位与含义3.2 内存请求的调度影响3.3 内存请求的特殊性 …

大型语言模型中的自动化思维链提示

摘要 大型语言模型&#xff08;LLMs&#xff09;能够通过生成中间推理步骤来执行复杂的推理任务。为提示演示提供这些步骤的过程被称为思维链&#xff08;CoT&#xff09;提示。CoT提示有两种主要范式。一种使用简单的提示语&#xff0c;如“让我们一步一步思考”&#xff0c;…

Private Set Generation with Discriminative Information(2211.04446v1)

1. 遇到什么问题&#xff0c;解决了什么遇到的问题现有差分隐私生成模型受限于高维数据分布建模的复杂性&#xff0c;合成样本实用性不足。深度生成模型训练依赖大量数据&#xff0c;加入隐私约束后更难优化&#xff0c;且不保证下游任务&#xff08;如分类&#xff09;的最优解…

C++编程语言入门指南

一、C语言概述 C是由丹麦计算机科学家Bjarne Stroustrup于1979年在贝尔实验室开发的一种静态类型、编译式、通用型编程语言。最初被称为"C with Classes"(带类的C)&#xff0c;1983年更名为C。它既具有高级语言的抽象特性&#xff0c;又保留了底层硬件操作能力&…

ZED相机与Foxglove集成:加速机器人视觉调试效率的实用方案

随着机器人技术的发展&#xff0c;实时视觉数据流的高效传输和可视化成为提升系统性能的重要因素。通过ZED相机&#xff08;包括ZED 2i和ZED X&#xff09;与Foxglove Studio平台的结合&#xff0c;开发者能够轻松访问高质量的2D图像、深度图和点云数据&#xff0c;从而显著提高…

目标检测新纪元:DETR到Mamba实战解析

&#x1f680;【实战分享】目标检测的“后 DEⱯ”时代&#xff1a;DETR/DINO/RT-DETR及新型骨干网络探索&#xff08;含示例代码&#xff09; 目标检测从 YOLO、Faster R-CNN 到 Transformer 结构的 DETR&#xff0c;再到 DINO、RT-DETR&#xff0c;近两年出现了许多新趋势&am…

【IOS】XCode创建firstapp并运行(成为IOS开发者)

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍XCode创建firstapp并运行 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷路…

class类和style内联样式的绑定 + 事件处理 + uniapp创建自定义页面模板

目录 一.class类的绑定 1.静态编写 2.动态编写 二.style内联样式的绑定 三.事件处理 1.案例1 2.案例2 四.uniapp创建自定义页面模板 1.为什么要这么做&#xff1f; 2.步骤 ①打开新建页面的界面 ②在弹出的目录下&#xff0c;新建模板文件 ③用HBuilderX打开该模板…

android 卡顿和丢帧区别

Android 卡顿&#xff08;Jank&#xff09;与丢帧&#xff08;Frame Drop&#xff09;的核心区别在于问题本质与用户感知&#xff0c;以下是分层解析&#xff1a; ️ 一、本质差异 维度卡顿&#xff08;Jank&#xff09;丢帧&#xff08;Frame Drop&#xff09;定义用户可感知…

【python实用小脚本-125】基于 Python 的 Gmail 邮件发送工具:实现高效邮件自动化

引言 在现代办公和开发环境中&#xff0c;邮件通信是一种重要的沟通方式。自动化发送邮件可以大大提高工作效率&#xff0c;例如发送通知、报告或文件。本文将介绍一个基于 Python 的 Gmail 邮件发送工具&#xff0c;它能够通过 Gmail 的 SMTP 服务器发送邮件&#xff0c;并支持…

gateway断言配置详解

一、Predicate - 断⾔ 1、简单用法 spring:cloud:gateway:routes:- id: after_routeuri: https://example.orgpredicates:- After2017-01-20T17:42:47.789-07:00[America/Denver] 2、自定义断言 新建类VipRoutePredicateFactory&#xff0c;注意VipRoutePredicateFactory名字…

基于大模型的尿毒症全流程预测与诊疗方案研究报告

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与方法 1.3 国内外研究现状 二、尿毒症相关理论基础 2.1 尿毒症的定义、病因与发病机制 2.2 尿毒症的症状与诊断标准 2.3 尿毒症的治疗方法概述 三、大模型技术原理与应用 3.1 大模型的基本概念与发展历程 3.2 大模型…

裸金属服务器租用平台-青蛙云

企业对服务器性能与灵活性的要求与日俱增。青蛙云M-启强裸金属服务器租用平台应运而生&#xff0c;为企业提供了一种兼具物理机性能和云计算弹性的解决方案。裸金属服务器租用平台的优势​(一)高配性能&#xff0c;无虚拟化开销​裸金属服务器直接运行在物理硬件之上&#xff0…

[Terence Tao访谈] AlphaProof系统 | AI嗅觉 | 研究生学习 | 庞加莱猜想(高维) | 复杂问题简单化

玩这些有趣的东西。通常情况下什么也得不到&#xff0c;你必须学会说&#xff1a;“好吧&#xff0c;再试一次&#xff0c;什么都没发生&#xff0c;我会继续前进。” DeepMind的AlphaProof系统 Q&#xff1a;DeepMind的AlphaProof系统是通过强化学习训练的&#xff0c;使用的…