-
-
[原创]14.滴水中级班(内核驱动)——任务段(上)
-
发表于: 2小时前 49
-
任务段这一块与操作系统有关,任务段不好理解,一定要认真细致地看。
无论是什么门,只要出现了权限切换,那么就伴随着堆栈操作,权限切换一定会变CS,比如3环现在切换到0环,那么CS一定会变,CS换了那么SS一定换,因为CS和SS是一对双胞胎、权限级别永远都是一致的。所以CS换了,SS就一定要换,SS换了,堆栈就一定要换,也就是说只要发生权限切换,那么这三样东西都会换。CS是哪里来的呢?我们在构造这些门的时候,我们是一定要指定CS的,所以我们可以这么理解,CS是我们通过中断门或者调用门指定的。ESP和SS这两个值是哪里来的呢?这就是这节课要讲的了——TSS。
这里再次强调一遍,TSS不是寄存器,不在CPU中,它是一个内存,它在内存中,大小是104字节,TSS里面都有什么呢?可以理解为TSS里面包含所有通用寄存器,如EDI、ESI、EBP、ESP、EBX、EDX、ECX、EAX等等以及所有的段寄存器、标志寄存器和EIPCR3以及一些ESP和SS。我们可以看成这个内存中存储了一大堆值,所有寄存器等东西都在这个TSS里面存储着了。104个字节存储的是一群寄存器的值。
intel的设计思想是这样的:在操作系统运行的时候,一定要进行任务的切换,intel所谓的任务实际上对应的是操作系统里面的线程,而大家都清楚,CPU里面的任务在操作系统里面就是线程。当程序执行的时候,当你想做一个新的任务,那么上下文环境是一定要发生变化的,不能用原来的寄存器的值了,如果要做新的事情,那么一定要用新的寄存器,那么这些新的寄存器怎么来呢?就是来自于TSS,把TSS里面所有的值读出来放到寄存器里,这样就OK了。当你要回来做原来的事情的时候,把原来的值存储到TSS中,然后再读取TSS就OK了。所以intel的设计初衷就是希望我们通过使用TSS来实现所谓的任务的切换,也就是所谓的线程的切换。但是操作系统并没有这样做,Windows没有这样做、Linux也没有这样做,所以我们学习TSS的时候要弄清楚intel的思想是什么、操作系统的思想是什么,届时会再讲操作系统的思想的。所以这里记住——TSS与任务切换没有关系,TSS的意义就是在于可以同时替换掉一堆寄存器。
当我们做调用门、中断门、陷阱门发生权限切换的时候,SS和ESP从哪里来的?就是从这里来的,所以0环、1环、2环就是下面的0~24字节,这里补充一下:虽然操作系统没有用到1环和2环,但是我们可以用,我们想进几环就进几环。主要是要理解本质。
这104个字节,CPU是如何找到TSS的呢?
TR寄存器(Task Register)是一个段寄存器,段寄存器有96位,段寄存器的值是怎么来的呢?是从段描述符中加载的,我们现在知道两张表,一个GDT表,一个IDT表,IDT表里面存储了三个门,GDT表里面存储的全都是段描述符,TR寄存器中的值是从TSS段描述符中加载出来的,既然叫段描述符,那么一定在GDT表里,所以这里已经有三个概念了。第一个概念是TSS任务段,在内存中,占用104个字节;第二个是TR段寄存器,有96位,在CPU中;TSS段描述符首先是个段描述符,所以在GDT表中。当CPU找TSS的时候,它直接找TR寄存器,TR寄存器的Base指向了这个TSS在哪,它的Limit指向了这个TSS一共有多大,所以CPU想找到TSS很容易,直接找TR寄存器就完事了,TR寄存器的值是哪里来的呢?是操作系统启动的时候,从段描述符中加载出来放到TR寄存器里的,就像其他的段寄存器一样,都是从GDT表中的段描述符中取出来,然后加到GDT表里的TR寄存器里。所以大家要弄清楚TSS、TR寄存器、TSS段描述符之间是什么样的关系。
刚才大家已经知道了TR寄存器里面的值是从TSS段描述符中取出来的,那么段描述符我们已经接触过很多了,比如代码段、数据段、系统段,TSS段描述符是系统段描述符中的一种,系统段描述符中可能是调用门、中断门、任务门,也可能是TSS段,所以TSS段描述符是系统段描述符中的一种。既然是系统描述符,那么高四字节的下标为12的位置一定是0,因为只有为0的时候才是系统段描述符。其他的那些与段描述符没有区别,当它的类型即高四个字节的第8~11位如果为9也就是1001的时候,就说明当前这个描述符是一个TSS段描述符;如果是1011的话就是B,那么它也是TSS段描述符;区别是如果是9的时候,说明这个段描述符没有加载到TR寄存器中,如果是B的时候,就说明这个段描述符已经加载到TR寄存器中了。这就是它俩的区别。
最后说一下如何读写TR寄存器,首先是三个概念:TSS、TR寄存器和TR段描述符,TR寄存器指向了TSS,因为TR.Base指向了TSS从哪里开始,TR.Limit指向了TSS有多大。如果用LTR的话,相当于从GDT表中找到了一个TSS段描述符,把这个段描述符加载到TR寄存器中,这就意味着TR寄存器中会有一个新的TR.Base和TR.Limit,但是只改到这一步,不会把TR.Base和TR.Limit指向的TSS同时改掉,它不改,你爱指哪就指哪,总之就是你只改TR寄存器,但是不改TSS。这是第一个说明的解释。
第二个说明的解释:LTR指令使用的时候,只能是系统层也就是0环中使用。
第三个说明:原来是9现在变成B,这个刚才已经提过了。
如果修改TSS,光用这两个指令是不行的,具体参考下一节课。