CPU原生支持的任务切换方式

2023-05-16

CPU 厂商原本计划的一种任务切换方法,并不是操作系统实例中任务切换的方法, 未采用的原因是此方法效率不高,现代操作系统很少用这种方法切换任务
为了支持多任务, CPU 厂商提供了 LDT TSS 这两种原生支持,他们要求为每个任务分别配一个 LDT TSS (这由咱们操作系统程序员来构建), LDT 中保存的是任务自己的实体资源,也就是数据和代码,TSS 中保存的是任务的上下文状态及三种特权级的栈指针、 I/O 位图等信息。既然 LDT TSS 用来表示任务,那么任务切换就是换这两个结构:将新任务对应的 LDT 信息加载到 LDTR寄存器,对应的 TSS 信息加载到 TR 寄存器。下面我们看看 CPU 是怎样进行任务切换的。
TSS CPU 用于保存任务的状态及任务状态的恢复,而 LDT 是任务的实体资源, CPU 厂商只是建议这样做,其实没有 LDT 的话也是可以的。比如我们可以把任务自己的段描述符放在 GDT 中,或者干脆采用平坦模型直接用那个 4GB 大小的全局描述符。任务的段放在 GDT,还是 LDT中,无非就是在用选择子选择它们时有区别,区别您懂的,就是选择子中 TI 位的取值,0 是从 GDT 中选择段描述符, 1是从 LDT中选择段描述符。描述符及描述符表只是逻辑上对内存区域的划分(当然这也包括其他各种属性,但对此来说并不重要),任务要想执行,归根结底都是用 cs : eip 指向这个任务的代码段内存区域以及 DS 指向其数据段内存区域,所以任务私有的实体资源不是必须放在它自的 LDT 中。综上所述, LDT 是可有可无的,真正用于区分一个任务的标志是 TSS ,所以用于任务切换的根本方法必然是和任务的 TSS 选择子相关
进行任务切换的方式有中断+任务门call jmp+任务门iretd

通过“中断+任务门”进行任务切换

其实咱们对采用中断这种方式进行任务切换早己熟悉了,目前的线程切换中用的就是时钟中断 中断
是定时发生的,因此用中断进行任务切换的好处是明显的。
• 实现简单。
• 抢占式多任务调度,所有任务都有运行的机会。
一个完整的任务包括用户空间代码及内核空间代码,这两种代码加起来才是任务的全局空间。另外,在 CPU 眼里, TSS 就代表一个任务,TSS 才是任务的标志, CPU 区分任务就是靠TSS 因此,只要 TR 寄存器中的 TSS 信息不换,无论执行的是哪里的指令,也无论指令是否跨越特权级(从用户态到内核态) CPU 都认为还是在同一个任务中
(1) 从该任务门描述符中取出任务的 TSS 选择子。
(2)用新任务的 TSS 选择子在 GDT 中索引 TSS 描述符
(3) 判断该 TSS 描述符的P位是否为1,为1表示该 TSS 描述符对应的 TSS 己经位于内存中 TSS描述符指定的位置,可以访问。否则p不为1表示该 TSS 描述符对应的 TSS 不在内存中,这会导致异常
(4) 从寄存器 TR 中获取旧任务的 TSS位置,保存旧任务(当前任务)的状态到旧 TSS 其中,任务状态是指 CPU 中寄存器的值,这仅包括 TSS 结构中列出的寄存器:8个通用寄存器, 6个段寄存器,指令指针寄存器eip ,栈指针寄存器 esp ,页表寄存器 cr3 和标志寄存器 eflags 等。
(5) 把新任务的 TSS 中的值加载到相应的寄存器中
(6) 使寄存器 TR 指向新任务的 TSS
(7) 将新任务(当前任务〉的 TSS 描述符中的P位置1
(8) 将新任务标志寄存器中 eflags NT 位置1
(9) 将旧任务的 TSS 选择子写入新任务 TSS 中“上一个任务的 TSS 指针”字段中
(10) 开始执行新任务。

call jmp 切换任务

(1) 首先,任务门描述符除了可以在 IDT 中注册,还可以在 GDT, LDT 中注册
(2) 其次,任务以 TSS 为代表,只要包括 TSS 选择子的对象都可以作为任务切换的操作数
综上所述,中断发生时,通过任务门进行任务切换的过程如下。
假设 TSS 选择子定义在 GDT 中第3个描述符位置:
call 0x0018 : 0x1234
(1 CPU 忽略偏移量 0x1234 ,拿选择子 0x0018到GDT 中索引到第3个描述符
(2 检查描述符中的P位,若为0,表示该描述符对应的段不存在,这将引发异常 同时检查该描述符的S与TYPE 的值,判断其类型, 如果是TSS描述符,检查该描述符的B位, B 位若为1将抛出 GP异常,即表示调用不可重入
(3 进行特权级检查,数值上“ CPL和TSS 选择子中的 RPL ”都要小于等于 TSS 描述符的 DPL ,否则抛出 GP 异常
(4 特权检查完成后,将当前任务的状态保存到寄存器 TR 指向的 TSS 中。
(5 加载新任务 TSS 选择子到 TR 寄存器的选择器部分,同时把 TSS 描述符中的起始地址和偏移量属性加载到 TR 寄存器中的描述符缓冲器中。
(6 将新任务 TSS 中的寄存器数据载入到相应的寄存器中,同时进行特权级检查,如果检查未通过,则抛出 GP 异常
(7 CPU 会把新任务的标志寄存器 eflags 中的NT位置为1
(8 将旧任务 TSS 选择子写入新任务 TSS 中的字段“上个任务的 TSS 指针”中,这表示新任务是被旧任务调用才执行的
(9 然后将新任务 TSS 描述符中的B位置为1以表示任务忙, 旧任务 TSS 描述符中的B位不变,依然保持为1,旧任务的标志寄存器 eflags 中的 NT 位的值保持不变,之前是多少就是多少
(10 开始执行新任务,完成任务切换

TSS是x86CPU 的特定结构,被用来定义“任务”,它是内置到处理器原生支持的多任务的一种形式
上文中, 介绍了 CPU 提供的多任务支持,每个任务拥有自己的 TSS ,每个任务也可以有自己的LDT ,看样子还是很简洁的,但为什么 Linux 未采用此方式呢?
上面的过程大概分成 10 步,还是直接用 TSS 选择子进行任务切换的步骤,这已经非常繁琐了,在每一次任务切换过程中, CPU 除了做特权级检查外,还要在 TSS 的加载、保存、设置B位,以及设置标志寄存器 eflags NT 位诸多方面消耗很多精力,这导致此种切换方式效能很低。
其次,常见的指令集有两大派系,复杂指令集 CISC 和精简指令集 RISC.x86 使用的指令集属于 CISC,在此指令集的发展过程中,工程师为了让程序员少写代码,把指令的功能做得越发强大,因此在阳SC多条指令才能完成的工作,在 CISC 中只用一条指令就完成了。看上去感觉很爽的样子,但这只是开发效率上的提升,执行效率却下降了,原因是:表面强大的功能是用内部复杂、数量更多的微操作换来的,也就是说, CISC 的强大需要更多的时钟周期作为代价。虽然 Intel 提供了 call jmp 指令实现任务切换,但这两个指令所消耗的时钟周期也是可观的,都是以百为单位的(据说已经达到 300+,我没测试过)。最后,一个任务需要单独关联一个 TSS, TSS 需要在 GDT 中注册, GDT 中最多支持 8192 个描述符,为了支持更多的任务,随着任务的增减,要及时修改 GDT ,在其中增减 TSS 描述符,修改过后还要重新加载 GDT 。这种频繁修改描述符表的操作还是很消耗 CPU 资源的。
以上是效率方面的原因,除了效率以外,还有便携性和灵活性等原因,不仅 Linux 未来用这种原生的任务切换方法,而且几乎所有 x86 操作系统都未来用
不幸的是,我们是在 CPU 制定的规则上编写程序的,因此始终脱离不了大规则的束缚,还高 件工作必须且只能用 TSS 来完成,这就是 CPU 向更高特权级转移时所使用的战地址,需要提前在 TSS 中写入导致转移到更高特权级的一种情况是在用户模式下发生中断, CPU 会由低特权级进入高特权级,这会发生堆梭的切换。当一个中断发生在用户模式(特权级 ),处理器从当前 TSSsso espO 成员中获取用于处理中断的堆枝。因此,我们必须创建一个 TSS ,并且至少初始化 TSS 中的这些字段尽管 CPU 提供了。、 个特权级,但我们效仿 Linux 只用其中的 个,内核处理特权级 o,用户进程处于特权级结论 我们使用 TSS 唯一的理由是为 特权级的任务提供枝

不过为了“应付”这一指标, Linux 为每个 CPU 创建一个 TSS ,在各个 CPU 上的所有任务共享同TSS ,各 CPU的TR寄存器保存各 CPU 上的 TSS ,在用 ltr 指令加载 TSS 后,该 TR 寄存器永远指向同一个 TSS ,之后再也不会重新加载 TSS 。在进程切换时,只需要把 TSS 中的 sso esp0更新为新任务的内核栈的段地址及栈指针。
您看,实际上 Linux TSS 的操作是一次性加载 TSS到TR,之后不断修改同 TSS 的内容,不再进行重复加载操作。
Linux TSS 中只初始化了 sso esp0和I/O位图字段,除此之外 TSS 便没用了,就是个空架子,不再做保存任务状态之用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CPU原生支持的任务切换方式 的相关文章

  • 数组删除元素

    在数组中删除值为val的元素 xff0c 因为数组在内存中是连续存储 xff0c 所以不能只删除元素 xff0c 而是在删除元素后还要使后边元素前移 在数组中删除元素有两种方法 xff1a xff08 1 xff09 暴力解法 xff08
  • STM32F103最小系统板引脚定义

    STM32F103最小系统原理图 本人初学stm32 若有误解之处 还望大佬们指正改进 感谢 STM32F103各引脚定义 可前往 STM32F103xCDE 数据手册 英文 的第三章 Pinouts and pin description
  • 基带面试题附答案

    请列举您知道的电阻 电容 电感品牌 xff08 最好包括国内 国外品牌 xff09 电容 xff1a 美国 xff1a AVX VISHAY 威世 日本 xff1a KOA 兴亚 Kyocera 京瓷 muRata 村田 Panasonic
  • nginx简介(一)

    背景 xff1a 前面说了准备围绕运维工程师所要学习的知识进行记录和分享 xff0c linux基础的记录是一个漫长的过程 xff0c 后面会时不时的记录下 今天准备拉一个分支 xff0c 介绍一下nginx的相关内容 xff0c 由于ng
  • 蓝桥杯嵌入式——第十二届蓝桥杯嵌入式国赛客观题

    1 填空题 嵌入式竞赛平台上板载的微控制器是 xff1a 3 级流水线 xff0c 具有 128 Kbytes的Flash存储空间 xff08 请在第一 二空格处填写10进制数值 xff09 解析 xff1a STM32G431RBT6采用
  • git pull 所有branch和tag并上传

    pull span class token function git span branch r span class token operator span span class token function grep span v sp
  • 双非渣本大三学生春招拿到实习Offer的经历

    从今年的2月底投简历开始到现在已经两个月了 xff0c 两个月的时间我经历了很多大大小小的笔试面试 xff0c 坎坎坷坷的也是终于拿到了美图的Offer xff0c 美团和头条好歹也都进了终面 xff0c 躺在备胎池里面 xff08 不打算
  • TX2超详细,超有用的刷机教程

    TX2超详细 xff0c 超有用的刷机教程 TX2被Nvidia官方称作是最快 xff0c 最节能的嵌入式AI计算设备 它的功耗小 xff0c 只有7 5W xff0c 体型也小 xff0c 只有一张信用卡那么大 xff0c 它是真正可以实
  • vscode 同步gitee远程仓库

    一 首先在gitee端创建远程仓库 二 在vscode中配置git信息 git config global user name 34 your name 34 git config global user email 34 your ema
  • QGC地面站参数调节

    校准 xff1a 1 选择机架 xff1a 一般用DJI Flame Wheel F450机架 xff0c 选择之后点击 应用并重启 xff1b 2 传感器校准 xff1a 无人机会重新连接地面站 xff0c 依次校准 磁罗盘 陀螺仪 xf
  • PX4初级教程

    链接 xff1a https pan baidu com s 1VIQcOQt I5 evMx1jnV0ZQ 提取码 xff1a 8niq
  • Qt Creator编写无人机地面站系统

    用户登录界面 将用户注册的账户信息如实填写 xff0c 然后输入验证码 xff0c 点击 xff02 登录 xff02 即可进入无人机地面站管理系统 xff0e 地面站界面
  • Mavlink自定义协议

    参照本人博客 xff1a 博客直达 浏览密码 xff1a N414 这里不做描述 xff0c 详细过程请移步本人博客
  • 狼群算法资源总结

    狼群算法介绍 xff1a 狼群算法的优化 狼群算法三维路径规划 xff1a 狼群算法三维路径规划Matlab
  • html+css+php+mysql实现注册+登录+修改密码(附完整代码)

    注 xff1a 转载及使用源代码请注明来源 xff01 如疑问可私信 xff01 目的 xff1a 在利用QT软件进行登录软件开发时 xff0c 就想要实现点击按钮跳转到指定网页进行注册以及修改密码等操作 xff0c 就像QQ客户端那样可以
  • Qt嵌入外部EXE程序,并显示在主界面中!

    一 获取程序句柄以及类 打开Visual Studio 进行查询 二 QT调用程序 H文件 span class token macro property span class token directive keyword ifndef
  • Cmake软件编译opencv报错,CMake Warning at cmake/OpenCVDownload.cmake:193 (message): FFMPEG: Download...

    当执行如下操作时 xff1a 出现下面报错 xff0c 在链接ipaddress com查询raw githubusercontent com地址 xff0c 然后将ip添加至C Windows System32 drivers etc h
  • MOT:MOTchallenge任务评价方法

    GT介绍 span class token number 1 1 span 912 484 97 109 0 7 1 span class token number 2 1 span 912 484 97 109 0 7 1 span cl
  • /bin/sh^M: 坏的解释器: 没有那个文件或目录

    在windows上面notepad 43 43 写的shell文件 xff0c 复制带Linux上面提示错误 bin sh M 坏的解释器 没有那个文件或目录 在命令行执行下面语句 xff1a span class token commen
  • 相机内参矩阵、外参矩阵、畸变矩阵

    1 相机针孔模型 图中 xff0c X坐标系是针孔所在坐标系 xff0c Y坐标系为成像平面坐标系 xff0c P为空间一点 xff0c 小孔成像使得P点在图像平面上呈现了一个倒立的像 齐次形式 xff1a 在此 xff0c 我们先暂时舍弃

随机推荐

  • STM32—驱动GY85-IMU模块

    GY85是一个惯性测量模块 xff0c 内部集成了三轴加速度计 三轴陀螺仪 电子罗盘 气压传感器等芯片 xff0c 用于测量和报告设备速度 方向 重力 xff0c 模块可以将加速度计 陀螺仪 电子罗盘等传感器的数据进行综合 xff0c 在上
  • MPU6050原始数据分析——学习笔记

    MPU6050原始数据分析 学习笔记 个人学习笔记MPU6050简介 原始数据分析加速度计陀螺仪代码 个人学习笔记 用于记录自己学习的成果 xff0c 并且分享给大家一起看看 希望对看到这篇的朋友有所帮助 MPU6050简介 MPU 605
  • DAY15 异常捕获

    DAY15 异常捕获 一 文件操作细节问题 1 1 参数encoding open file mode 61 r encoding 61 None encoding 设置文本文件的编码或者解码方法 xff08 将数据写入到文件之前会自动编码
  • x86-从实模式到保护模式(总结)

    总结主要针对最后一章的内容 xff0c 最后一张的程序使用的是平坦模式 代码段和数据段都是从0x00000000到0xffffffff xff0c 能够访问4GB的地址空间 使用平坦模式的好处 xff1a 不用频繁的在段与段之间进行切换 代
  • Docker 部署 Prometheus & Grafana (监控主机进程)

    目录 1 环境介绍 xff1a 2 部署 主机进程 监控1 使用 Docker 部署 Grafana2 部署并启动 prometheus3 下载 process exporter4 创建并编辑文件 process name yaml5 在
  • 【Docker】报错:Got permission denied while trying to connect to the Docker daemon socket at unix:///var/

    报错原因 在VMWARE中安装的centos中查看容器Docker所安装的镜像命令时即执行 docker images 时虚拟机报错 xff0c 该用户没有此类权限 错误 xff1a Got permission denied while
  • linux ubuntu 彻底卸载包,清理linux软件卸载残留

    使用以下命令清理残留配置 xff0c 其实就是删除残留的 rc文件 dpkg span class token parameter variable l span span class token operator span span cl
  • list和array 访问不连续index

    python中内置数据类型list与numpy array都是常会用到的两种数据结构 二者在访问变量中不连续index时处理方式有所不同 array array访问不连续index的方式非常简单 xff0c 只需要用定义好的索引直接截取ar
  • TVM Windows conda 安装

    TVM Windows 安装 简介 本篇博客主要目的是帮助大家在windows平台上安装好tvm xff0c 并且可以顺利使用 因为有项目需要使用tvm xff0c 同时自己需要用windows做一些测试 xff0c 因此想要在window
  • 探讨ros下的cmakelists文件的编写

    文章目录 cmakelists文件整体架构分块讲解1 CMake版本2 软件包名称3 查找相关的CMake包4 消息 服务 动作生成器 cmakelists文件整体架构 所需CMake版本 xff08 cmake minimum requi
  • git 克隆指定分支

    git clone b 分支名 仓库地址
  • 【NVIDIA】Jetson Xavier NX镜像烧录

    设备信息 我的设备是Jetson Xavier NX xff1b 准备工作 鼠标 键盘 显示器SD卡 32GB至少 网线 xff08 也可以wifi xff09 官方教程 xff1a https developer nvidia com e
  • Android GPS学习 (二) :GPS 服务启动以及初始化流程

    扫码关注 xff0c 一起学习 1 GPS 服务启动 SystemServer java的startOtherServices方法中添加LocationManagerService方法的代码如下 frameworks base servic
  • docker运行ubuntu22.04出现异常(转载)

    原文链接 xff1a https xyz uscwifi xyz post PRTc2ZYZx 参考 xff1a docker Why I cannot run 96 apt update 96 inside a fresh ubuntu
  • 为什么执行同一个程序每次输出的变量地址是不一样的

    首先看一下下面的代码 include lt stdio h gt int main int a 61 1 printf 34 p n 34 amp a return 0 然后我就很疑惑 xff0c 为什么每次的地址都是不一样的 为什么会有这
  • 中断的基本概念

    异常和中断 概念 xff1a 程序执行过程中CPU会遇到一些特殊情况 xff0c 是正在执行的程序被 中断 xff0c cpu中止原来正在执行的程序 xff0c 转到处理异常情况或特殊事件的程序去执行 xff0c 结束后再返回到原被中止的程
  • 8086CPU结构与功能

    微处理器的外部结构 微处理器的外部结构如下图所示 8086CPU片有40个管脚 微处理器通过这些引脚与外部的逻辑部件连接 完成信息的交换 CPU的这些引脚称为微处理器级的总线 功能 与存储器之间交换信息 指令及数据 与I O设备之间交换信息
  • 8086微处理器的寄存器组织

    8086CPU内部有14个16位的寄存器 按功能可以分为8个通用寄存器 4个段寄存器和两个控制寄存器 通用寄存器 通用寄存器可以分为两类 数据寄存器 AX BX CX DX 和地址寄存器 变址寄存器 SI DI SP BP 8086CPU有
  • python dict setdefault()方法

    描述 Python 字典 setdefault 函数和 get 方法 类似 如果键不存在于字典中 xff0c 将会添加键并将值设为默认值
  • CPU原生支持的任务切换方式

    CPU 厂商原本计划的一种任务切换方法 xff0c 并不是操作系统实例中任务切换的方法 未采用的原因是此方法效率不高 xff0c 现代操作系统很少用这种方法切换任务 为了支持多任务 xff0c CPU 厂商提供了 LDT TSS 这两种原生