操作系统是利用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的其它方面将会在后续章节中逐步说明。

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

  1. 一步步编写操作系统 61 任务状态段 TSS

    I/O位图是位于TSS中的,它可以存在也可以不存在,它只是用来设置对某些特定端口的访问,没有它的话便默认为禁止访问所有端口.正是由于它可有可用,所以TSS的段界限TSS limit(即实际大小-1)并 ...

  2. 一步步编写操作系统 71 直接操作显卡,编写自己的打印函数71-74

    一直以来,我们在往屏幕上输出文本时,要么利用bios中断,要么利用系统调用,这些都是依赖别人的方法.咱们还用过一个稍微有点独立的方法,就是直接写显存,但这貌似又没什么含量.如今我们要写一个打印函数了, ...

  3. 一步步编写操作系统 69 汇编语言和c语言共同协作 70

    由于有了上一节的铺垫,本节的内容相对较少,这里给大家准备了两个小文件来实例演示汇编语言和c语言相互调用. 会两种不同语言的人,只是掌握了同一件事物的两种表达方式.人在学习一种新语言时,潜意识里是建立了 ...

  4. 一步步编写操作系统 62 函数调用约定

    由于我们要将c语言和汇编语言结合编程啦,所以一定会存在汇编代码和c代码相互调用的问题,有些事情还是要提前交待给大家的,本节就是要给大家说下函数调用规约中的那些事儿. 函数调用约定是什么? 调用约定,c ...

  5. 一步步编写操作系统 57 门、调用门与RPL序 2

    接上文: 提供了4种门的原因是,它们都有各自的应用环境,但它们都是用来实现从低特权级的代码段转向高特权级的代码段,咱们这里也只讨论有关特权级的功用: 1.调用门 call和jmp指令后接调用门选择子为 ...

  6. 任务状态段TSS及TSS描述符、局部描述符表LDT及LDT描述符

    1.TSS介绍 在一个多任务环境中,当发生了任务切换,需保护现场,因此每个任务的应当用一个额外的内存区域保存相关信息,即任务状态段(TSS):TSS格式固定,104个字节,处理器固件能识别TSS中元素 ...

  7. 一步步编写操作系统 35 内存为何要分页

    一直以来我们都直接在内存分段机制下工作,目前未出问题看似良好,的确目前咱们的应用过于简单了,就一个loader在跑,能出什么问题呢.可是想像一下,当我们物理内存不足时会怎么办呢?比如系统里的应用程序过 ...

  8. 全局描述表GDT、任务状态段TSS、局部描述表LDT之间的关系

    最近在学习哈工大操作系统时碰到了TSS的相关知识,感觉还牵涉到了GDT.LDT的相关知识,这里大概把相关的知识总结一下,以供以后参考 全局描述符表GDT 在计算机从实模式(16位)转换到保护模式(32 ...

  9. 一步步编写操作系统 45 linux的elf可执行文件中的段和节

    接上文,为了描述清楚文件格式的本质,咱们先从最基本的"段"说起. 程序中最重要的部分就是段(segment)和节(section),它们是真正的程序体,是真真切切的程序资源,所以下 ...

最新文章

  1. 辽师836c语言真题,2018年武汉科技大学考研真题硕士研究生入学考试试题
  2. Linux shell条件判断if中的-a到-z的意思
  3. 随笔--2011.12.21
  4. 使用SourceTree拉取代码出现Permission denied (publickey)
  5. 8 线程安全且高效的单例模式
  6. 使用CloudIDE搭建简单java环境
  7. r语言和python爬虫谁厉害_R语言中,RCurl优势在哪儿,做爬虫的话用Python还是RCurl效率高?...
  8. clock()函数的使用
  9. xcode 重新来过openssl项目历程
  10. 全局变量不能放在头文件其中
  11. 电力监控服务器维修,地铁电力监控系统(PSCADA)发生故障应该如何处理
  12. 《金融学》笔记 第七章 商业银行
  13. linux 无盘 重新生成内核,Linux无盘系统_尐惢
  14. java三角形类_java 三角形类 Triangle的用法详解
  15. 高仿微信拍照,视频录制-----JCameraView
  16. AboutSpace
  17. 【CCAI大咖秀】李德毅院士:机器人产业需做好交互认知
  18. 微信原生组件|基于小程序实现音视频通话
  19. 压力测试软件怎么用,鲁大师温度压力测试如何使用
  20. java开发中JWT、JWE、JWS 、JWK 都是干啥的

热门文章

  1. prometheus 笔记
  2. 投资股权众筹项目,至少需要关注6个方面
  3. linux rz批量上传
  4. UCScript——C++集成脚本
  5. NSHashTable and NSMapTable
  6. 10 个十分难得的 javascript 开发经验
  7. pytorch中的squeeze和unsqueeze
  8. Linux启动过程以及初始化
  9. decimal这个数据类型的用法,保证你看懂
  10. android中的 listview,Android中ListView的初步认识(一)