(第三章 九)通过调用门进行有特权级变换的转移(二)

(第三章 9)通过调用门进行有特权级变换的转移(二)

本文展示《(第三章 9)通过调用门进行有特权级变换的转移(一)》的主要流程

 

跳入保护模式

 

[SECTION .s32]-->

[SECTION .ring3]-->

调用门-->[SECTION .sdest]-->

[SECTION .la]

 

跳回实模式

 

***************************************************************************************************************

1、本段([SECTION .s32])属性:

[SECTION .gdt]

LABEL_DESC_CODE32:     Descriptor 0,    SegCode32Len-1, DA_C+DA_32   ;非一致,32

SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT

 

 

[SECTION .s32];32位代码段,由实模式跳入
	...
	(10行0列显示PMMessage,即"In Protect Mode now. ^-^")
	...
	mov	ax,	SelectorTSS
	ltr	ax	; 在任务内发生特权级变换时要切换堆栈,而内层堆栈的指针存放在当前任务的TSS中,所以要设置任务状态段寄存器TR

	push	SelectorStack3	;ss
	push	TopOfStack3	;esp
	push	SelectorCodeRing3	;cs
	push	0		;eip
	retf			;ring0~~>ring3跳转

 

     从[SECTION .s32]跳到[SECTION .ring3]是从高到低特权级的跳转!

     本来ret(retf)是和call配合使用的指令,用来返回断点。这里单独使用,可以理解为“从[SECTION .32]返回[SECTION .ring3]”,用来从高特权级跳转到低特权级,具体过程如书P59叙述,P60图3.21所示:

1)检查被调用者堆栈中保存的CS中的RPL(对应代码push SelectorCodeRing3),以判断返回时是否要变换特权级。

      此时发现当前特权级为0,转到特权级为3的代码段,发生了特权级变化(高-->低)。

 

2)加载被调用者堆栈上的cs和eip(SelectorCodeRing3和0)。

      (此时怎么进行特权级检验???)

此时,就返回断点了——在本程序中cs和eip已经指向[SECTION .ring3]段了。

 

3)此retf不含参数,不用增加esp跳过参数。当前堆栈是被调用者([SECTION .s32])堆栈。

 

4)加载被调用者([SECTION .s32)堆栈中的ss和esp,切换到调用者([SECTION .ring3])堆栈。此时,被调用者([SECTION .s32)堆栈中的ss和esp被丢弃,但由于等会儿还要从低特权级转换回高特权级,故需要将“0级堆栈的SelectorStack和TopOfStack”提前放入TSS。

 

此时,当前堆栈从被调用者([SECTION .s32])堆栈变成了调用者([SECTION .ring3)堆栈了。

5)此retf不含参数,不用增加esp跳过参数。当前堆栈是调用者([SECTION .ring3)堆栈。

6)检查ds、es、fs、gs的值,如果其中哪一个寄存器指向的段的DPL小于CPL(此规则不适用于一致代码段),那么一个空描述符被加载到该寄存器。我想:此时这几个寄存器都被置空描述符了吧~(???)

***************************************************************************************************************

2、本段([SECTION .ring3])属性:

[SECTION .gdt]

LABEL_DESC_CODE_RING3: Descriptor 0, SegCodeRing3Len-1, DA_C+DA_32+DA_DPL3

LABEL_DESC_STACK3:     Descriptor 0,       TopOfStack3, DA_DRWA+DA_32+DA_DPL3

 

SelectorCodeRing3 equ LABEL_DESC_CODE_RING3 - LABEL_GDT + SA_RPL3

SelectorStack3 equ LABEL_DESC_STACK3 - LABEL_GDT + SA_RPL3

 

 

[SECTION .ring3]
	...
	(14行0列显示'3')
	...
	call	SelectorCallGateTest:0	;调用调用门中的目标代码段,如果在目标段最后有retf可以返回这个断点,但我们不这么做。我们在目标段中继续进入局部段[SECTION .la],然后返回实模式
	...

     这个跳转是“通过调用门 从低到高特权级”!

 

     1)step1:   指示调用门的选择子的RPL<=门描述符DPL & 当前代码段的CPL<=门描述符的DPL。

     此时,在[SECTION .ring3]中。因为[SECTION .ring3]是非一致代码段,故在从[SECTION .s32]跳转到该段时,已经设置CPL=3  (参见http://chuanwang66.iteye.com/admin/blogs/1075472)。即是说,此时CPL=3。

     call SelectorCallGateTest:0调用调用门,由SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT + SA_RPL3)可知,调用门的RPL为3。即是说,此时RPL=3。

     又调用门的DPL=3。

     由上面三段的描述有: CPL<=调用门DPL & RPL<=调用门DPL。故可以访问到调用门中的目标段选择子了^_^

 

     2)step2:   CPL>=DPL,RPL不作检查(因为RPL总被清0)

     现在,CPL=3; 目标段[SECTION .sdest]的DPL=0,且为非一致代码段。故CPL>=DPL(RPL不作检查),满足特权级检查,跳转到[SECTION .sdest],哈哈

 

     3)跳转后,CPL被修改为0(原来为3)

     因为CPL=目标段[SECTION .sdest]的DPL(=0),因此,跳转到[SECTION .sdest]后CPL=0

 

***************************************************************************************************************

3、本段([SECTION .sdest])属性:

[SECTION .gdt]

 

; 门                                            目标选择子,       偏移, DCount, 属性

LABEL_CALL_GATE_TEST: Gate  SelectorCodeDest,          0,      0, DA_386CGate + DA_DPL3

LABEL_DESC_CODE_DEST:  Descriptor 0,  SegCodeDestLen-1, DA_C+DA_32   ;非一致,32

 

SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT + SA_RPL3

SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT

 

 

[SECTION .sdest]	;调用门目标段
	...
	(12行0列显示'C')
	...
	mov	ax,	SelectorLDT
	lldt	ax

	jmp SelectorLDTCodeA:0	;跳到LDT中定义的局部段

 

     [SECTION .sdest]段是非一致32位段,而且DPL=0,并且当前CPL=0。而此后用到的“DPL”和“选择子中的RPL”都为0,均在最高特权级上跳转,不需要设计权限检查了!啊,是不是突然感觉轻松许多了呢^_^

***************************************************************************************************************

4、本段([SECTION .la])属性:

[SECTION .gdt]

LABEL_DESC_LDT:        Descriptor 0,          LDTLen-1, DA_LDT   ;LDT

SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT

 

 

[SECTION .ldt]

LABEL_LDT_DESC_CODEA: Descriptor       0,     CodeALen - 1,   DA_C + DA_32 ; Code, 32 位

SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL

 

 

 

[SECTION .la]
	...
	(13行0列显示'L')
	...
	jmp	SelectorCode16:0	;准备经由16位代码段跳回实模式
 

 

***************************************************************************************************************

参考:

http://www.socvista.com/bbs/viewthread.php?tid=1748&extra=page%3D2    整个程序简要流程
http://blog.****.net/axman/archive/2009/12/09/4969131.aspx                           retf指令实现从高特权级到低特权级的跳转