《自己动手写操作系统》第三章 pmtest4源码解析——利用门调用实现特权级转移

摘要:本节,我们将通过分析pmtest4来实现利用调用门进行段间转移。


一、背景与原理

在汇编语言中,我们不能执行这样的指令:mov ds 100h和mov cs,ax;也就是说,段寄存器的值,是不能像通用寄存器一样,随意赋值的。具体的cs寄存器而言,它涉及到程序的控制转移,需要借助jmp、call、ret、sysenter,sysexit,int n,iret来实现,或者通过中断和异常来完成。我们知道,jmp和call指令,实现的跳转形式如下jmp selector:offset,其中,selector可以指向:


1)目标代码段
2)调用门描述符(->目标代码段选择子)
3)TSS(->目标代码段选择子)
4)任务门(->tss-->目标代码段)
其中第一类属于直接转移,剩下三种属于简介转移。


我们知道,通过jmp和call指令的一般转移,对于非一致性代码段,只能在同特权级之间进行。如果想在不同特权级之间自由切换,需要借助门描述符或者TSS。门描述符有任务门、中断门、陷阱门、异常门:其中中断门和陷阱门属于特殊的调用门。门描述符(目标选择子+入口地址+属性)的结构可以参考这里:http://blog.csdn.net/trochiluses/article/details/20312479


但是,call和jmp在控制转移的时候,作用不是完全相同的,如果代码段A通过调用门G转移到代码段B,call和jmp对应的特权级规则如下:
也就是说,通过call和调用门,可以实现从低特权级转移到高特权级。


2.程序流程概览:

pmtest4这个程序,我们主要将讲解如何通过调用门实现,低特权级代码向高特权级别的代码转移——就像鲤鱼越龙“门”。


实模式初始段:初始化GDT中的相关数据,为进入保护模式做准备,通过一个长跳转jmp,进入保护模式
保护模式下32b代码段:打印初始化字符,通过调用门,进入目标代码段32b
目标代码段:打印字符C,然后通过retf指令,返回32b代码段
32b代码段:通过jmp,进入LDT中的codeA段,、
LDT中的codeA段:打印字符L,通过jmp指令,回到16b代码段
16b代码段:回到实模式下

通过以上分析,我们知道:只需要在pmtest3的代码中添加目标代码段和门描述符就可以了。

二、代码解惑



按照以往的惯例,我们仍然采用分段的方式,分析代码:


1.GDT中注意:

上述多了一个调用门的选择子和描述符,它也被放在GDT之中


2.调用门目标段中的retf指令和ret指令有哪些不同?
retf指令的意义
ret 弹出一个参数,给ip,返回
retf 弹出2个参数,一个给 ip,一个给 cs
iref 弹出 3个参数,一个给 ip,一个 给 cs ,一个 给 flag标志位
他们都是返回调用点的,看你调用的时候,用的什么调用的,是 call 段内转移 ,还是call 段间转移,还是int 调用中断。

3.对于实模式第一个段的分析:
1)、为什么需要在这里初始化各个段描述符的相关属性呢?
答:开始,没有进入保护模式。同时CS的值已经被刷新。目前,程序运行的代码已经被dos加载到内存的相关部分,GDT的表才刚刚落户,所以我们才刚刚得到GDT的基地址,所以我们在这个时候刷新各个段的描述符属性。
2)、为何要加载GDT?
加载GDT是能够进行保护模式寻址的关键,不然我们仅仅知道段选择子,还是没法找到段描述符。GDTR中包含32b段基地址和16b段限长,这一点我们已经在gdt段中定义过了。
3)、重新回到实模式以后,是否有必要刷新ds、es、ss、sp等?
这是程序编写的一般流程,即使不刷新,也不一定会产生错误,我们可以亲自尝试一下。

4.保护模式
1)、这个段完成了什么功能?
显示初始化的字符串;通过调用门完成打印字母‘C’;通过跳入局部任务,打印字母‘L’;定义了一个局部程序DisplayReturn
2)、为什么要在jmp之前,设置ldt?
和GDT的设定是同样的道理。

实际代码如下:

%include	"head.inc"
org 0100h
	jmp LABEL_BEGIN

[SECTION .gdt]
;GDT							base,	length,	attr

LABEL_GDT:      Descriptor         0,                0, 0 
LABEL_DESC_NORMAL:	Descriptor		0,	0ffffh,		DA_DRW
LABEL_DESC_CODE16:	Descriptor		0,	0FFFFH,		DA_C
LABEL_DESC_DATA:	Descriptor		0,	SegDataLen-1,	DA_DRW
LABEL_DESC_STACK:	Descriptor		0,	TopOfStack,		DA_DRWA+DA_32
LABEL_DESC_CODE32:	Descriptor		0,	SegCode32Len-1,	DA_C+DA_32
LABEL_DESC_CODE_DEST: Descriptor	0,	SegCodeDestLen-1,DA_C+DA_32
LABEL_DESC_LDT:		Descriptor		0,	LDTLen-1,	DA_LDT
LABEL_DESC_VIDEO:	Descriptor	0B8000h,	0ffffh,	DA_DRW
LABEL_CALL_GATE_TEST:	Gate	SelectorCodeDest,0,0,DA_386CGate + DA_DPL0

GdtLen	equ	$-LABEL_GDT
GdtPtr	dw	GdtLen-1;注意,长度都是实际长度减1
		dd	0	;段基地址,注意,这里之所以没有直接制定,是因为还没有确定保护模式下gdt的基地址

;选择子
SelectorData		equ		LABEL_DESC_DATA		-	LABEL_GDT	
SelectorCode16		equ		LABEL_DESC_CODE16	-	LABEL_GDT
SelectorCode32		equ		LABEL_DESC_CODE32	-	LABEL_GDT
SelectorStack		equ		LABEL_DESC_STACK	-	LABEL_GDT 
SelectorNormal		equ		LABEL_DESC_NORMAL	-	LABEL_GDT 
SelectorLDT			equ		LABEL_DESC_LDT		-	LABEL_GDT 
SelectorCodeDest 	equ		LABEL_DESC_CODE_DEST -	LABEL_GDT 
SelectorCallGateTest equ	LABEL_CALL_GATE_TEST -	LABEL_GDT 
SelectorVideo		equ		LABEL_DESC_VIDEO	-	LABEL_GDT
;end of section gdt
;--------------------------------------------------------------
[SECTION .data]
[BITS 32]
ALIGN 32
LABEL_SEG_DATA:
	SPValueInRealModel	dw	0
PMMessage:		db		"Coming into protect mode now !",0
OffsetPMMessage	equ	PMMessage - $$
StrTest:		db	"ABCDEFGHIJKLMNOPQRSTUVWXYZ",	0
OffsetStrTest	equ	StrTest - $$
SegDataLen			equ		$ - LABEL_SEG_DATA 
;end of section data
;-----------------------------section:global stack------------------
[SECTION .gs]
ALIGN	32
[BITS 32]
LABEL_SEG_STACK:
	times	512	db	0
TopOfStack	equ	$-LABEL_SEG_STACK-1
;----------------------section:LDT----------------------------------
[SECTION .ldt]
align	32
[bits	32]
LABEL_SEG_LDT:

LABEL_DESC_CODEA:	Descriptor	0,CodeALen -1,DA_C+DA_32


LDTLen		equ		$- LABEL_SEG_LDT

SelectorCodeA 	equ		LABEL_DESC_CODEA - LABEL_SEG_LDT + SA_TIL

;end of ldt segment
;-------------------------------section:codeA------------------------
[section	.codeA]
align	32
[bits	32]	
LABEL_SEG_CODEA:
	mov		ax,SelectorVideo
	mov		gs,ax

	mov		ah,0ch
	mov		al,'L'
	mov		edi,(2*80+0)*2
	mov		[gs:edi],ax
	jmp		SelectorCode16:0
CodeALen equ	$-LABEL_SEG_CODEA 
;end of secion codeA
;------------------------------section:s16 begin---------------------
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
	xchg 	bx,bx
	mov		ax,cs
	mov		ds,ax
	mov		es,ax
	mov		ss,ax
	mov		sp,0100h
	
	mov		[LABEL_GO_BACK_TO_REAL+3],ax
	mov		[SPValueInRealModel],sp

	;for segment code32
	xor		eax,eax
	mov		eax,cs
	shl		eax,4
	add		eax,LABEL_SEG_CODE32;
	mov		word	[LABEL_DESC_CODE32 +2],ax
	shr		eax,16
	mov		byte	[LABEL_DESC_CODE32 + 4],al
	mov		byte	[LABEL_DESC_CODE32 + 7],ah

	;for segment code16
	xor		eax,eax
	mov		ax,cs
	shl		eax,4
	add		eax,LABEL_SEG_CODE16;
	mov		word	[LABEL_DESC_CODE16 +2],ax
	shr		eax,16
	mov		byte	[LABEL_DESC_CODE16 + 4],al
	mov		byte	[LABEL_DESC_CODE16 + 7],ah

	;for segment data
	xor		eax,eax
	mov		eax,ds
	shl		eax,4
	add		eax,LABEL_SEG_DATA;
	mov		word	[LABEL_DESC_DATA +2],ax
	shr		eax,16
	mov		byte	[LABEL_DESC_DATA + 4],al
	mov		byte	[LABEL_DESC_DATA + 7],ah

	;for segment ldt
	xor		eax,eax
	mov		eax,ds
	shl		eax,4
	add		eax,LABEL_SEG_LDT;
	mov		word	[LABEL_DESC_LDT +2],ax
	shr		eax,16
	mov		byte	[LABEL_DESC_LDT + 4],al
	mov		byte	[LABEL_DESC_LDT + 7],ah
	
	;for segment codeA
	xor		eax,eax
	mov		eax,ds
	shl		eax,4
	add		eax,LABEL_SEG_CODEA;
	mov		word	[LABEL_DESC_CODEA  +2],ax
	shr		eax,16
	mov		byte	[LABEL_DESC_CODEA + 4],al
	mov		byte	[LABEL_DESC_CODEA + 7],ah
	
	;for segment stack
	xor		eax,eax
	mov		eax,ds
	shl		eax,4
	add		eax,LABEL_SEG_STACK;
	mov		word	[LABEL_DESC_STACK +2],ax
	shr		eax,16
	mov		byte	[LABEL_DESC_STACK+ 4],al
	mov		byte	[LABEL_DESC_STACK+ 7],ah

	;no need for video base
	;for segment dstcode
	xor		eax,eax
	mov		ax,cs
	shl		eax,4
	add		eax,LABEL_SEG_CODE_DEST
	mov		word	[LABEL_DESC_CODE_DEST +2],ax
	shr		eax,16
	mov		byte	[LABEL_DESC_CODE_DEST +4],al
	mov		byte	[LABEL_DESC_CODE_DEST +7],ah

	xor 	eax,eax
	mov		ax,ds
	shl		eax,4
	add		eax, LABEL_GDT
	mov		dword	[GdtPtr +2 ],eax

	lgdt	[GdtPtr]

	cli

	in 		al,92h
	or		al,02h
	out		92h,al

	mov		eax,cr0
	or		eax,1
	mov		cr0,eax

	jmp		dword SelectorCode32:0
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY:	;come here from protect model
	mov		ax,cs
	mov		ds,ax
	mov		es,ax
	mov		ss,ax

	mov		sp,[SPValueInRealModel]

	in		al,92h
	and		al,11111101b
	out		92h,al

	sti

	mov		ax,4c00h
	int		21h
;end of section .s16
;------------------------section:code32,start of protect model--------
[SECTION .s32]
[BITS	32]
LABEL_SEG_CODE32:
		mov		ax,SelectorVideo
		mov		gs,ax
		
		mov		ax,SelectorData
		mov		ds,ax


		mov		ax,SelectorStack
		mov		ss,ax
		
		mov		esp,TopOfStack

		mov		ah,0ch
		xor		esi,esi
		xor		edi,edi
		mov		esi,OffsetPMMessage
		mov		edi,(80*11+0)*2
		cld
.loopPmMessage:
		lodsb
		test	al,al
		jz	.end
		mov		[gs:edi],ax
		add		edi,2
		jmp	.loopPmMessage

.end:	;

		call	DispReturn
		call	SelectorCallGateTest:0

		;Load LDT
		mov		ax,SelectorLDT
		lldt	ax
			
		jmp		SelectorCodeA:0	


;function: read and print 8 byte from es:0
TestRead:
		xor		esi,esi
		mov		ecx,8
.loopForEightBype:
		mov		al,[es:esi]
		call	DispAL
		inc		esi
		loop	.loopForEightBype
		
		call	DispReturn
		
		ret; be sure of this

;funtion:
	;write 8byte to es:OffsetStrTest
	;input:es
TestWrite:
		push	esi
		push	edi
	
		xor		esi,esi
		xor		edi,edi
		mov		esi,OffsetStrTest
		cld

	.loopForEightBype:
		lodsb	;ds:si->al
		test	al,al
		jz	.end
		mov		[es:edi],al
		inc		edi
		jmp		.loopForEightBype
	.end:
		pop		edi
		pop		esi

		ret


;funtion DispAL
;	display the number in AL
;input: AL-the number
;		edi-the position to display
;modified:ax,edi
DispAL:
	push	ecx
	push	edx
	mov		ah,0ch
	mov		dl,al
	shr		al,4
	mov		ecx,2
.begin:
	and		al,01111b
	cmp		al,9
	ja		.moreThanNine
	add		al,'0'
	jmp		.end
.moreThanNine:
	sub		al,0ah
	add		al,'A'
.end:
	mov		[gs:edi],ax
	add		edi,2

	mov		al,dl
	loop	.begin
	add		edi,2

	pop		edx
	pop		ecx
		
	ret
;DispAL

;function DispReturn
;if edi=(a*80 + b)*2
;then edi=(a*80 + 80)*2
DispReturn:
	push	eax
	push	ebx
	mov		eax,edi	
	mov		bl,160
	div		bl
	and		eax,0ffh;
	inc		eax
	mov		bl,160
	mul		bl
	mov		edi,eax
	pop		ebx
	pop		eax

	ret
;end for function DispReturn
	SegCode32Len	equ		$-LABEL_SEG_CODE32
;end of section .s32

;---------------------section s16code,before return to real-----------

[SECTION .s16code]
ALIGN	32
[BITS 16]
LABEL_SEG_CODE16:
	;return to real model
	mov		ax,SelectorNormal 
	mov		ds,ax
	mov		es,ax
	mov		fs,ax
	mov		gs,ax
	mov		ss,ax

	mov		eax,cr0
	and	al,11111110b
	mov		cr0,eax

LABEL_GO_BACK_TO_REAL:
	jmp		0:LABEL_REAL_ENTRY;
Code16Len	equ	$-LABEL_SEG_CODE16

;end of section s16code
;---------------------section:sdest---------------------------------
[section	.sdest]
[bits	32]

LABEL_SEG_CODE_DEST:
	mov		ax,SelectorVideo
	mov		gs,ax

	mov		edi,(80*12+0)*2
	mov		ah,0ch
	mov		al,'C'
	mov		[gs:edi],ax

	retf
SegCodeDestLen	equ		$-LABEL_SEG_CODE_DEST













你可能感兴趣的:(自己动手写操作系统,调用门,段间转移)