下面是一些关于特权级转换的说明,其中重点介绍特权级转换时的检查,类似于变换特权时的堆栈切换,任务切换过程和任务的嵌套等未加说明,可参阅有关专著.段内转移和实模式下一样,不涉及特权级的转换和任务间的切换,所以重点说一说任务内段间的转移和任务间的转移.
任务内相同特权级的转移:
段间直接转移和段间直接调用:
1.检查目标地址指针内的选择子指示的描述符是否为空,目标代码段描述符不能为空描述符,即该选择子的高14位不能为0
2.由选择子内的TI位(第2位)决定是从GDT还是从LDT中读出目标代码段的描述符
3.检查描述符类型是否正确
4.普通代码段,要求CPL=DPL,RPL<=DPL;一致代码段,要求CPL>=CPL
5.目标代码段描述符中的P位必须为1
6.把目标代码段描述符中的段基址、段限、属性装入CS的高速缓冲寄存器中
7.检查目标地址的偏移是否越过目标代码段的段界限,这也是不允许的,即目标地址的偏移不允许越过该代码段
8.装入指令指针寄存器EIP,并把CPL装入CS内的RPL字段
任务内相同特权级的转移途径: 任务内相同特权级的转移可用段间直接或间接转移指令JMP和段间直接或间接调用指令CALL、段间返回指令RET、中断指令INT、中断返回指令IRET.其中利用段间接转移指令JMP和段间调用指令CALL的任务内相同特权级的转移是指用到了调用门.
任务内不同特权级的转移:
任务内不同特权级的转移分为向内层转移和向外层转移
通过调用门(下面的都是指间接转移):
一.向内层转移:
1.首先要检查调用门,必须符合CPL<=DPL,RPL<=DPL
2.检查目标地址指针内的选择子指示的描述符是否为空,目标代码段描述符不能为空描述符,即该选择子的高14位不能为0
3.由选择子内的TI位(第2位)决定是从GDT还是从LDT中读出目标代码段的描述符
4.检查描述符类型是否正确,调整RPL=0
5.这里的检查类似于任务内相同特权级的转移中的第4步,但这里的DPL不是调用门的DPL,而是调用门内选择子所指向的目标代码段描述符的DPL,因为对于段间转移指令JMP和段间调用指令CALL所做的检查不一致,所以分别加以描述:
1) 对于使用调用门的段间转移指令JMP : 相同与上面的段间直接转移和段间直接调用的检查,由于RPL=0(经调整后为0),所以总是认为RPL<=DPL;所以对于普通代码段,CPL=DPL时,为相同特权级的转移,对于一致代码段,CPL>=DPL也发生相同特权级的转移.所以说不能用JMP指令实现任务内不同特权级的转移.
2) 对于使用调用门的段间调用指令CALL: 同样,由于RPL=0(经调整后为0),所以总是认为RPL<=DPL;对于一致代码段,当CPL>=DPL时发生相同特权级的转移;对于普通代码段,当CPL=DPL时同样是相同特权级的转移;这两种情况都是把原CS和EIP保存到当前堆栈;只有当CPL>DPL时,才发生向内层的转移,同时使CPL=DPL(很重要的一步),要切换堆栈.原CS和EIP的内容保存在内层堆栈
6.目标代码段描述符中的P位必须为1
7.把目标代码段描述符中的段基址、段限、属性装入CS的高速缓冲寄存器中
8.检查目标地址的偏移是否越过目标代码段的段界限,这也是不允许的,即目标地址的偏移不允许越过该代码段
9.分别装入CS段寄存器和指令指针寄存器EIP,并把CPL装入CS内的RPL字段
二.向外层转移:
1.从堆栈中弹出返回地址,如果返回的目标地址的选择子的RPL>CPL,即向外层转移.
2.越过内层堆栈中的参数从堆栈中弹出外层堆栈的指针,装入SS和ESP.从此恢复外层堆栈
3.调整ESP,跳过调用之前压入的参数.
4.检查数据段寄存器DS、ES、FS和GS,保证寻址的段在外层是可访问的,否则装入一个空选择子.
5.返回继续执行
如果是相同特权级的转移,只有第1、5步;如果RET指令不带立即数,只有第1、4、5步
任务内不同特权级的转移途径:段间调用指令CALL通过调用门实现从外层到内层的转移,段间返回指令RET实现内层到外层的转移.
致此,任务内转移就结束了,下面是任务间的转移.
任务切换:
实际上任务的切换是比较麻烦的,但庆幸的是对于它的特权级检查却比较简单:
一.直接用TSS进行任务切换
采用访问数据段相同的特权级检查规则:访问TSS段描述符的CPL必须小于等于TSS段描述符的DPL,并且指示TSS段描述符的选择子的RPL必须小于等于TSS段描述符的DPL.
二.用任务门进行任务切换
也是采用访问数据段相同的特权级规则:访问任务门的CPL必须小于等于任务门的DPL,并且指示任务门的选择子的RPL必须小于等于任务门的DPL,同时还要求任务门内的选择子必须指示GDT中的可用TSS段描述符(任务门的偏移丢弃不要).
访问数据段时的检查:
1.选择子不能为空
2.选择子指示的描述符只能是数据段描述符和可读可执行的代码段或一致代码段的描述符
3.对于数据段描述符和可读可执行的代码段描述符,需检查CPL<=DPL,RPL<=DPL
4.选择子所指示的段必须存在
访问堆栈段时的检查:
1.选择子不能为空
2.选择子所指示的描述符必须是可读可写的数据段描述符
3.在此要求RPL=CPL=DPL,即每一个特权级下都有自己独立的堆栈段,以实现隔离保护
4.选择子所指示的段必须存在
本文地址:http://com.8s8s.com/it/it29477.htm