一步步编写操作系统 53 任务状态段TSS介绍

操作系统是利用PCB来维护所有任务的,包括进程和线程,但cpu提供的是TSS,linux系统可没用它,因为效率太低。但是还是要了解下TSS才清楚操作系统中某些操作的原因。

本节中所讲的特权级与它有着密不可分的联系,TSS作用不止涉及特权级,还包括任务寄存器环境,任务管理相关的内容,为了不干扰大家,这里只介绍和特权级相关的内容,待将来咱们用到更多内容时再和大伙儿细说。

TSS,即Task State Segment,意为任务状态段,它是处理器在硬件上原生支持多任务的一种实现方式,也就是说处理器原本是想让操作系统开发厂商利用此结构实现多任务,人家处理器厂商已经提供了多任务管理的解决方案,尽管后来操作系统并不买账^_^,这是后话,以后再议。TSS是一种数据结构,它用于存储任务的环境。咱们一睹为快,见图

TSS是每个任务都有的结构,它用于一个任务的标识,相当于任务的身份证,程序拥有此结构才能运行,这是处理器硬件上用于任务管理的系统结构,处理器能够识别其中每一个字段。该结构看上去也有点复杂,里面众多寄存器都囊括到这104字节中啦,其实这104字节只是TSS的最小尺寸,根据需要,还可以再接上个IO位图,这些内容将在后面章节用到时补充。这里目前只需要关注28字节之下的部分,这里包括了3个栈指针,这是怎么回事呢。

在没有操作系统的情况下,可以认为进程就是任务,任务就是一段在处理器上运行的程序,相当于某个计算机高手在脱离操作系统的情况下所写的代码,它能让计算机很好地运行。在有了操作系统之后,程序可分为用户程序和操作系统内核程序,故,之前完整的一个任务也因此被分为用户部分和内核部分,由于内核程序是位于0特权级,用户程序位于3特权级,所以,一个任务按特权级来划分的话,实质上是被分成了3特权级的用户程序和0特权级的内核程序,这两部分加在一起才是能让处理器完整运行的程序,也就是说完整的任务要历经这两种特权的变换。所以,我们平时在Linux下所写程序只是个半成品,咱们只负责完成用户态下的部分,内核态的部分由操作系统提供。

任务是由处理器执行的,任务在特权级变换时,本质上是处理器的当前特权级在变换,由一个特权级变成了另外一个特权级。这就开始涉及到栈的问题了,处理器固定,处理器在不同特权级下,应该用不同特权级的栈,原因是如果在同一个栈中容纳所有特权级的数据时,这种交叉引用会使栈变得非常混乱,并且,用一个栈容纳多个特权级下的数据,栈容量有限,这很容易溢出。举个例子,处理器位于0特权级时要用0特权级的栈,3特权级下也只能用3特权级的栈。

每个任务的每个特权级下只能有一个栈,不存在一个任务的某个特权级下存在多个同特权级栈的情况。也就是说,一共4个特权级,一个任务“最多”有4个栈。既然一个TSS代表一个任务,每个任务又有4个栈,那为什么TSS中只有3个栈:ss0和esp0、ss1和esp1、ss2和esp2?它们分别代表0级栈的段选择子和偏移量、1级栈的段选择子和偏移量、2级栈的段选择子和偏移量。大家看,我在前面说的一个任务最多拥有4个栈,并不是所有的任务都是这样。

要想搞清楚这个问题,得先弄明白TSS中记录的3个栈是用来干吗的。

刚才已经说过,特权级在变换时,需要用到不同特权级下的栈,当处理器进入不同的特权级时,它自动在TSS中找同特权级的栈,你懂的,TSS是处理器硬件原生的系统级数据结构,处理器当然知道TSS中哪些字段是目标栈的选择子及偏移量。

特权级转移分为两类,一类是由中断门、调用门等手段实现低特权级转向高特权级,另一类则相反,是由调用返回指令从高特权级返回到低特权级,这是唯一一种能让处理器降低特权级的情况。

对于第1种——特权级由低到高的情况,由于不知道目标特权级对应的栈地址在哪里,所以要提前把目标栈的地址记录在某个地方,当处理器向高特权级转移时再从中取出来加载到SS和ESP中以更新栈,这个保存的地方就是TSS。处理器会自动地从TSS中找到对应的高特权级栈地址,这一点对开发人员是透明的,咱们只需要在TSS中记录好高特权级的栈地址便可。

也就是说,除了调用返回外,处理器只能由低特权级向高特权级转移,TSS中所记录的栈是转移后的高特权级目标栈,所以它一定比当前使用的栈特权级要高,只用于向更高特权级转移时提供相应特权的栈地址。进一步说,TSS中不需要记录3特权级的栈,因为3特权级是最低的,没有更低的特权级会向它转移。

不是每个任务都有4个栈,一个任务可有拥有的栈的数量取决于当前特权级是否还有进一步提高的可能,即取决于它最低的特权级别。比如3特权级的程序,它是最低的特权级,还能提升三级,所以可额外拥有2、1、0特权级栈,用于将特权分别转移到2、1、0级时使用。2特权级的程序,它还可以提升两级,所以可额外拥有1、0特权级栈,用于将特权级分别转移到1、0级时使用。以此类推,1特权级的程序,它可以额外拥有0特权级栈,0特权级已经是至高无上了,只有这一个0级栈。以上所说的低特权级转向高特权级的过程称为“向内层转移”,想想4个特权级划分的同心圆就知道了,高特权级位于里面。

对于第2种——由高特权返回到低特权级的情况,处理器是不需要在TSS中去寻找低特权级目标栈的。其中一个原因我想您已经猜到了:TSS中只记录2、1、0特权级的栈,假如是从2特权级返回到3特权级,上哪找3特权级的栈?另一方面的原因是,低特权级栈的地址其实已经存在了,这是由处理器的向高特权级转移指令(如int、call等)实现的机制决定的,换句话说,处理器知道去哪里找低特权级的目标栈,等我把后面内容“啰嗦完”您就知道了。

由于特权级向低转移后,处理器特权级有了变化,同样也需要将当前栈更新为低特权级的栈,它如何找到对应的低特权级栈呢。正常情况下,特权级是由低向高转移在先,由高向低返回在后,即只有先向更高特权级转移,才能谈得上再从高特权级回到低特权级,否则没有“去”就谈不上“回”(宁可被骂啰嗦我也要说清楚)。当处理器由低向高特权级转移时,它自动地把当时低特权级的栈地址(SS和ESP)压入了转移后的高特权级所在的栈中(随着以后深入学习大家会明白这一点),所以,当用返回指令如retf或iret从高特权级向低特权级返回时,处理器可以从当前使用的高特权级的栈中获取低特权级的栈段选择子及偏移量。由高特权级返回低特权级的过程称为“向外层转移”。

当下次处理器再进入到高特权级时,它依然会在TSS中寻找对应的高特权级栈,而TSS中栈指针值都是固定的,每次进入高特权级都会用重复使它们。也就是说,即使曾经转移到高特权级下用过高特权级栈,处理器也不会自动把该高特权级栈指针更新到TSS中,因为在从高特权级返回时,处理器需要把栈更新为低特权级的栈选择子及esp指针,而原先在段寄存器SS和寄存器esp中高特权级下的栈段选择子及指针会被处理器自动丢弃。换句话说,如果想保留上一次高特权级的栈指针,咱们得自己手动更新TSS中相应栈的数据。

对啦,有没有同学有疑问,上面光说处理器从TSS中找更高特权级的栈地址,那处理器是怎样找到TSS的?

TSS是硬件支持的系统数据结构,它和GDT等一样,由软件填写其内容,由硬件使用。GDT也要加载到寄存器GDTR中才能被处理器找到,TSS也是一样,它是由TR(Task Register)寄存器加载的,每次处理器执行不同任务时,将TR寄存器加载不同任务的TSS就成了。至于怎么加载以及相关工作原理,目前咱们用不到,还是放在后面说比较合适。

您看,正是由于处理器提供了硬件方面的框架,所以很多工作都是“自动”完成的,虽然操作系统看上去很底层的样子,但其实也属于“应用型”开发。

好啦,TSS中有关特权级的内容就说到这,为了不干扰大家学习特权级,TSS的其它方面将会在后续章节中逐步说明。

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

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

相关文章

动手学无人驾驶(6):基于IMU和GPS数据融合的自车定位

在上一篇博文《动手学无人驾驶(5):多传感器数据融合》介绍了如何使用Radar和LiDAR数据对自行车进行追踪,这是对汽车外界运动物体进行定位。 对于自动驾驶的汽车来说,有时也需要对自身进行更精确的定位,今天…

【Codeforces - 798C】 Mike and gcd problem(思维,贪心)

题干: Mike has a sequence A  [a1, a2, ..., an] of length n. He considers the sequence B  [b1, b2, ..., bn] beautiful if the gcd of all its elements is bigger than 1, i.e. . Mike wants to change his sequence in order to make it beauti…

一步步编写操作系统 48 加载内核1

其实,我们等了这一刻好久好久,即使我不说,大家也有这样的认识,linux内核是用c 语言写的,咱们肯定也要用c语言。其实...说点伤感情的话,今后的工作只是大部分(99%)都要用c语言来写&am…

Coursera自动驾驶课程第1讲:Welcome to the self-driving cars specialization

本专栏为Coursera自动驾驶课程笔记,B站上也有配套课程视频,对自动驾驶技术感兴趣的朋友可以看看。 本讲对应视频: https://www.bilibili.com/video/BV1WE411D74g?p1https://www.bilibili.com/video/BV1WE411D74g?p2https://www.bilibili.…

Coursera自动驾驶课程第2讲:The Requirements for Autonomy

上一讲《Coursera自动驾驶课程第1讲:Welcome to the self-driving cars specialization》对本课程进行了整体概述,同时回顾了自动驾驶汽车的发展历史。 从本讲我们开始进入正式的学习,我们将首先了解到如何划分自动驾驶汽车等级、以及自动驾…

一步步编写操作系统 51 加载内核4

咱们的内容都是连栽的,如果您没看过我之前的文章,本节您是看不懂的。 接上节。 介绍完内核初始化的函数kernel_init后,本节代码部分还差一点点没说啦,下面看代码: …略 179 ;在开启分页后,用gdt新的地址…

Coursera自动驾驶课程第3讲:Self-Driving Hardware and Software Architectures

在上一讲《Coursera自动驾驶课程第2讲:The Requirements for Autonomy》中我们了解到了如何划分自动驾驶汽车等级、以及自动驾驶三大模块:感知、决策和执行。 本讲我们将学习新的模块:自动驾驶汽车的硬件和软件架构。 B站视频链接&#xff…

一步步编写操作系统 54 CPL和DPL入门1

我们在工作中,公司都给员工配有员工卡,此员工卡就是员工身份的“标签”,用它来出入公司、食堂就餐等。给公司创造价值的是员工的生产力,不是员工卡,员工卡只是公司人事部门管理员工的一种手段而已。 现在说计算机&…

Coursera自动驾驶课程第4讲:Safety Assurance for Autonomous Vehicles

在上一讲《Coursera自动驾驶课程第3讲:Self-Driving Hardware and Software Architectures》中我们了解了自动驾驶汽车常用的传感器和硬件组件、软件系统。 本讲我们将学习新的模块,也是自动驾驶汽车最重要的模块之一:安全模块。 B站视频链…

【Codeforces - 1000C】Covered Points Count(思维,离散化,差分)

题干: You are given nn segments on a coordinate line; each endpoint of every segment has integer coordinates. Some segments can degenerate to points. Segments can intersect with each other, be nested in each other or even coincide. Your task i…

Coursera自动驾驶课程第5讲:Vehicle Dynamic Modeling

在上一讲《Coursera自动驾驶课程第4讲:Safety Assurance for Autonomous Vehicles》中我们了解了自动驾驶汽车中一个非常重要的模块:安全模块。 本讲我们将学习新的模块:汽车运动学和动力学模块。(这部分可能需要一定的理论力学和…

Java同步锁——lock与synchronized 的区别【转】

在网上看来很多关于同步锁的博文,记录下来方便以后阅读 一、Lock和synchronized有以下几点不同: 1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,synchronized是在JVM层面…

Coursera自动驾驶课程第6讲:Vehicle Longitudinal Control

在上一讲《Coursera自动驾驶课程第5讲:Vehicle Dynamic Modeling》中我们了解了汽车运动学和动力学模块。 本讲我们继续学习新的模块:汽车纵向控制。具体地,我们将学习PID控制算法,看看该算法是如何在自动驾驶汽车中应用的。 B站…

Java并发:线程共享变量可见性原理

0、线程安全性:线程安全性包括两个方面,①可见性。②原子性。 0.1、线程之间的通信:线程的通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种共享内存和消息传递。 (1)在共…

Coursera自动驾驶课程第7讲:Vehicle Lateral Control

在上一讲《Coursera自动驾驶课程第6讲:Vehicle Longitudinal Control》中我们了解了如何使用PID算法进行汽车纵向控制。 本讲我们继续学习新的模块:汽车横向控制。具体地,我们将学习三种控制算法:Pure pursuit,Stanle…

Coursera自动驾驶课程第8讲:Basics of 3D Computer Vision

在上一讲《Coursera自动驾驶课程第7讲:Vehicle Lateral Control》中我们了解了如何对汽车进行横向控制。 本课程第一个篇章就暂时告一段落了,接下来我们开始学习新的篇章。 课程第二个篇章是状态估计和定位模块。不过在这里我做了一下调整,我…

Coursera自动驾驶课程第9讲:Visual Features Detection Description and Matching

在上一讲《Coursera自动驾驶课程第8讲:Basics of 3D Computer Vision》中我们学习了计算机视觉基本知识。 本讲我们将学习计算机视觉中的视觉特征模块。 B站视频链接:https://www.bilibili.com/video/BV1PE411D72p 文章目录1. Introduction to Image f…

Coursera自动驾驶课程第10讲:Feedforward Neural Networks

在上一讲《Coursera自动驾驶课程第9讲:Visual Features Detection Description and Matching》中我们学习了如何进行图像特征检测,特征匹配以及如何构建视觉里程计来估计相机的运动。 本讲我们将学习神经网络模块,关于神经网络或深度学习网上…

守护进程和守护线程

对于JAVA而言,一般一个应用程序只有一个进程——JVM。除非在代码里面另外派生或者开启了新进程。 而线程,当然是由进程开启的。当开启该线程的进程离开时,线程也就不复存在了。 所以,对于JAVA而言,线程是完全可以由自…

Coursera自动驾驶课程第11讲:2D Object Detection

在上一讲《Coursera自动驾驶课程第10讲:Feedforward Neural Networks》中我们学习了神经网络的基础知识,包括损失函数,梯度下降,正则化,卷积网络等。 本讲我们将学习深度学习的一个重要应用:图像目标检测。…