-
-
[原创]15.滴水中级班(内核驱动)——任务段(下)
-
发表于: 1小时前 49
-
本节课要实现的就是任务切换,通俗点说就是一次性切换一堆寄存器,不要把它和任务强制联系到一起。
TSS里面存储了所有寄存器相关的值;TR寄存器是当CPU想要使用TSS内存里的这些寄存器的值的时候,通过TR寄存器来找到TSS,TR寄存器的Base指向了TSS在哪里,TR.Limit指定了当前的TSS一共有多大,TR寄存器的值是从GDT表里面加载的,GDT表里面存储了某一个所谓的TSS段描述符,当系统启动的时候,把这个段描述符的数据加载到TR寄存器中,通过TR寄存器我们就可以找到这个TSS了。
这一节课开始不知道为什么画质低的可怕,将就着看吧。
首先是第一个link,当你一次性切换一堆寄存器的时候,这个link存储的是就是原来的104个字节的段选择子,这个值不用我们填充,当我们切换的时候,由CPU和相关硬件来为我填充,下面有三组,分别是esp0和ss0、esp1和ss1、esp2和ss2。这些数字后缀就是不同级别环对应的不同的esp和ss属性。而这里因为我们不是中断门和调用门,所以我们不需要用到这些值,全部填为0就行。CR3这个值是必须填的,CR3现在还不能解释,等后面讲到页的知识的时候会细说,现在只需要知道是个寄存器就行。还有个是EIP,EIP这个概念很重要,我们通过TSS可以一次性替换一堆寄存器,里面也包括EIP,而EIP存储的是下一次代码执行的位置,所以这个EIP必须提供,而其他的诸如eax等给不给都无所谓。注意,这里说的不给是指填充为0而不是删除。代码执行切换的时候,一旦切换了,所有的寄存器都会发生变化,只要权限发生变化,那么堆栈一定发生变化,ESP的值也是需要给定的。再有就是这些段寄存器的值也需要给
FS的值3A和3B、CS也是对应的一些值如8、SS也是,比如10。
ES和DS永远都是23、无论0环还是3环。
最后的那个没有加注释的值,就是所谓的I/O映射图又叫I/O权限位图,这个Windows在2000年以后就不用了,这个值是从操作系统中现有的结构体中提取出来的。
TR寄存器的值都是从GDT表里面拿出来段描述符才放进去。高四个字节的23位,D位记得始终为1,D位为1代表Limit的界限是4KB,为0代表Limit的界限是字节。以前做实验的时候都是1,但是记住这里是0,因为Limit指向的TSS的是以字节为单位的,所以大家按照这个表格就可以构造出TSS的段描述符出来,实验里就写在一个空白的位置就OK了。第一步准备104个字节赋好正确的值,第二步准备好段描述符并将其写到GDT表里,第三步修改TR寄存器,
LTR指令有三个特殊的地方:1.只在0环中执行。2.值修改TR寄存器的值。
现在的情况是我们要把其他所有寄存器统统给改掉,如果我们想达到这一步,很显然我们要使用别的指令,这里就是使用CALL FAR和JMP FAR。同样是JMP,如果是代码段就只修改这两个寄存器,如果是任务段,就把所有的寄存器都改掉。
这里留了一道题,就是CALL指令没有写回去的代码,这里就是让我们自己去理解CALL和JMP是如何切回来的,如果彻底理解了,那么就说明我们的任务段掌握好了,否则就是学不会。查资料优先查白皮书。
我们的段描述符位置和视频演示的位置可能不一样,具体还是要看我们自己的代码。
我们接下来的操作是为了找到CR3的值,因为CR3的值是必须提供的
下断点给CR3赋值,执行发现可以,但是这里是停留在断点的位置了,也不能往后运行,因为回去的代码没写,继续执行只会蓝屏。
能够用CALL和JMP正确切换任务并且回去,大家回去之后做做实验。效果就拉满了。