忆杰的博客

忆杰的博客

保护模式6:特权级转换的任务切换

上一篇我们已经演示了特权级变换, 这一篇我们讲讲任务切换, 任务切换的话, 主要是特权级要注意, 如果特权级设置有错的话, 会崩溃.


关于这个任务切换可以通过TSS进行任务切换, 或者通过任务门进行任务切换, 如果是通过TSS进行任务切换的话, 可以使用Jmp或者段间转移指令CALL进行任务切换, 对于TSS的访问权限同数据段, 所以只有同级或者更内层的特权级才可以进行任务切换. 显然还有其他需求, 所以可以改用任务门进行切换.

如果Jmp或者CALL指向一个任务门描述符, 那么就按照数据段的访问规则检测任务门,对于TSS中的DPL却是忽略的, 还有任务门内的偏移是无效的. 这个和调用门有区别,要注意, 如果符合规则, 那么就可以开始任务切换了..

任务切换这个东西的话, 不能够递归, 任务切换又切换到自己上面, 这是不行的,当然如果是用jmp指令进行任务切换的话, 不进行链接, 这个就不算递归了, 只有CALL才算

对于Jmp和CALL都一样, 要求切换的任务必须是可用任务, 这个可以自己去修改段描述符,在代码中我们就修改了段描述符, 在测试任务返回演示任务的时候我们将原来的演示任务,从忙置为清闲, 才可以进行切换.

所以关于这个任务切换的话, 也没有太多难搞定的东西了, 主要是特权级的问题, 如果特权级不对就不能够做任务切换, 不过也没有问题, Bochs里面会提示的, 遇到崩溃了Bochs有提示.依照提示改好就行.. 没有太多可说的..

说说下面这个代码的逻辑含义, 首先在实模式下初始化该初始化的东西, 然后切换到保护模式的16位段在这个保护模式的代码段中, jmp到一个32位代码段, 然后在这个32位代码段中,  初始化测试任务的CS:EIP和演示任务的SS:ESP, LDTR, IOPL, 然后通过CALL切换到测试任务.

测试任务的话也没有做什么东西, 就是显示下自己的特权级, 当然是CS 和SS都是一级的, 所以当前特权级就是一级了. 显示完自己的特权级后, 然后就通过call又切换回演示任务, 当然在切换之前, 要将演示任务的TSS描述符从忙改为闲, 这个是用一个别名段来做到的.

切换到演示任务的时候, 再显示下自己的特权级, 当然现在特权级就是0级了, 然后切换到16位段, 从16位段切换到实模式, 然后搞定. 程序退出!

代码的逻辑含义的话, 就这么点东西, 还是那句话, 任务切换的时候必须注意特权级.还和以前一样, 有图有真相.

        http://www.joenchen.com/JoenTools/TaskSwitching.rar

  
 

;============================================================================
	;演示保护模式下的任务切换
	;MASM9下编译. Link9.编译选项请参见 makefile  TAB = 8
;============================================================================
	.686p
	Include pm.inc
	option casemap:none
Stack_Len	equ	1024		;堆栈大小
;============================================================================
GdtSeg		Segment use16		;全局描述符表
;				;段基址	;段界限			;属性
Dummy:			Descriptor	0, 	0, 		0				;空的描述符
Normal:			Descriptor	0, 	0ffffh,		 DA_DRW 			;规范段描述符
g_CodeTempDesc:		Descriptor 	0,	0ffffh, 	 DA_C				;非一致代码段16位
g_VideoDesc:		Descriptor	0b8000h,0ffffh, 	 DA_DRW or DA_DPL3		;显存段(可读写)
g_Stack0Desc:		Descriptor	0, 	Stack_Len-1,	 DA_DRW or DA_32		;0环堆栈32
g_DemoCodeDesc:		Descriptor	0,	DemoCodeSegLen-1, DA_C or DA_32			;32位代码段
g_DemoDataDesc:		Descriptor	0,	DemoDataSegLen-1,DA_DRW or DA_32		;Demo数据段
g_DemoTssDesc:		Descriptor	0,	DemoTssSegLen-1, DA_386TSS			;演示任务TSS段描述符
g_DemoTssAliasDesc:	Descriptor	0,	DemoTssSegLen-1, DA_DRW or DA_DPL1 or DA_32	;演示任务TSS段的别名段
g_TestTssDesc:		Descriptor	0,	TestTssSegLen-1, DA_386TSS			;测试任务TSS段描述符
g_TestStack1Desc:	Descriptor	0,	Stack_Len-1, 	 DA_DRW or DA_DPL1 or DA_32	;1环堆栈段
g_TestCodeDesc:		Descriptor	0,	TestCodeSegLen-1,DA_C or DA_32 or DA_DPL1	;32位测试代码段
g_TestTssAliasDesc:	Descriptor	0, 	TestTssSegLen-1, DA_DRW or DA_32		;TSS别名数据段
g_GdtAliasDesc:		Descriptor	0,	GDTLen-1,	 DA_DRW or DA_32 or DA_DPL1	;GDT别名段
g_TestLdtDesc:		Descriptor	0,	LdtTestSegLen -1,DA_LDT				;测试代码段的LDT描述符
;----------------------------------------------------------------------------
;任务门			段选择子		入口	参数个数	属性
g_TestTask: 	Gate 	g_TestTssSelector,_TestCodeBegin,	0, 	DA_TaskGate		;386任务门指向测试任务
g_DemoTask: 	Gate 	g_DemoTssSelector,_DemoEnd,		0, 	DA_TaskGate or DA_DPL1	;386任务门从测试任务返回
;----------------------------------------------------------------------------
GDT_Ptr		word	GDTLen-1				;VGDT
		dword	0
_IDT_Ptr        fword   0                       		;VIDT
_RegSp		word	?					;用于保存SS:SP
_RegSs		word	?
;----------------------------------------------------------------------------
NormalSelector		equ	Normal 			- GdtSeg			;规范段选择子
g_CodeTempSelector	equ	g_CodeTempDesc 		- GdtSeg			;代码段选择子
g_Stack0Selector	equ	g_Stack0Desc		- GdtSeg			;0环堆栈段选择子
g_DemoDataSelector	equ	g_DemoDataDesc		- GdtSeg			;Demo数据段选择子
g_TestStack1Selector	equ	g_TestStack1Desc	- GdtSeg + SA_RPL1		;测试任务段的1环选择子
g_VideoSelector		equ	g_VideoDesc  		- GdtSeg 			;LDT视频段选择子
g_DemoCodeSelector	equ	g_DemoCodeDesc		- GdtSeg			;32位演示代码段选择子
g_DemoTssAliasSelector	equ	g_DemoTssAliasDesc	- GdtSeg + SA_RPL1		;演示任务的别名段
g_DemoTssSelector	equ	g_DemoTssDesc		- GdtSeg			;TSS演示段描述符选择子
g_TestTssSelector	equ	g_TestTssDesc		- GdtSeg			;TSS测试段描述符选择子
g_TestCodeSelector	equ	g_TestCodeDesc		- GdtSeg + SA_RPL1		;32位测试代码段选择子
g_TestTssAliasSelector	equ	g_TestTssAliasDesc	- GdtSeg			;任务段别名段选择子
g_TestTaskSelector	equ	g_TestTask		- GdtSeg			;任务门选择子
g_TestLdtSelector	equ	g_TestLdtDesc		- GdtSeg			;测试代码段的LDT
g_GdtAliasSelector	equ	g_GdtAliasDesc		- GdtSeg + SA_RPL1		;GDT别名段
GDTLen			equ	$ - GdtSeg						;GDT长度
GdtSeg		Ends
;============================================================================
LdtTestSeg		Segment use32			;测试任务段的LDT
L_TestDataDesc:		Descriptor	0,	TestDataSegLen-1, DA_DRW or DA_DPL1	;测试任务数据段

L_TestDataSelector	equ	L_TestDataDesc - LdtTestSeg + SA_TIL			;测试代码的数据段
LdtTestSegLen		equ	$ - LdtTestSeg
LdtTestSeg		Ends
;============================================================================
Stack0		Segment use32
	byte	Stack_Len dup (0)
Stack0		Ends
;============================================================================
Stack1		Segment use32
	byte	Stack_Len dup (0)
Stack1		Ends
;============================================================================
TestDataSeg	Segment use32				;测试代码段的数据段
SzTestMessage	byte	"Test Task Privilege level: 0x", 0
TestDataSegLen		equ	$ - TestDataSeg
TestDataSeg	Ends
;============================================================================
DemoDataSeg	Segment use32				;Demo代码段的数据段
SzDemoMessage	byte	"Test Task Privilege level: 0x", 0
DemoDataSegLen		equ	$ - DemoDataSeg
DemoDataSeg	Ends
;============================================================================
IdtSeg		Segment use32				;中断描述符表
IdtSegLen		equ	$ - IdtSeg
IdtSeg		Ends
;============================================================================
TestCodeSeg	Segment use32				;测试代码段

_TestCodeBegin	equ	$ - TestCodeSeg			;测试代码段入口
TestCodeBegin	Proc

	mov	ax, g_VideoSelector
	mov	es, ax
	mov	ax, L_TestDataSelector
	mov	ds, ax
	cld
;----------------------------------------------------------------------------
	;显示调用任务的CS,
	mov	esi, offset SzTestMessage
	mov	ecx, sizeof SzTestMessage - 1
	mov	edi, 80 * 2 * 5 + 5 * 2			;5行5列

@@:	lodsb
	mov	ah, 0ch					;显示字符串1
	stosw
	loop	@b
;----------------------------------------------------------------------------
	mov	ax, cs
	and	al, 11b
	xor	cl, cl
	shl	al, 7
	rcl	cl, 1					;将特权级的高位移动过来
	add	cl, '0'

	sal	al, 1
	rcl	al, 1
	add	al, '0'
	mov	ah, 0ch
	shl	eax, 16
	mov	al, cl
	mov	ah, 0ch					;打印特权级
	stosd
;----------------------------------------------------------------------------
	;将任务由忙到可用
	mov	ax, g_GdtAliasSelector			;GDT别名段
	mov	fs, ax
	mov	ebx, offset g_DemoTssDesc		;DEMO描述符
	mov	al, byte ptr fs:[ebx+5]			;置任务为可用任务
	and	al,0f0h
	or	al, 9h					;将任务置为可用
	mov	byte ptr fs:[ebx+5], al
;----------------------------------------------------------------------------
	;改变任务的执行位置, 比较邪恶
	mov	ax, g_DemoTssAliasSelector
	mov	fs, ax					;fs-->临时代码别名段
	mov	esi, offset DemoTss
	mov	eax, _DemoEnd
	mov	dword ptr fs:[esi+TSS.regEip], eax
;----------------------------------------------------------------------------
	CALL32	g_DemoTask, 0				;返回0环
TestCodeBegin 	Endp
TestCodeSegLen	equ	$ - TestCodeSeg
TestCodeSeg	Ends
;============================================================================
DemoCodeSeg	Segment use32				;演示代码段

_DemoBegin		equ	$ - DemoCodeSeg
DemoBegin	Proc					;32位代码段入口

	mov	ax, g_TestTssAliasSelector		;TSS别名段
	mov	ds, ax
	mov	ebx, offset TestTss
;----------------------------------------------------------------------------
	;初始化演示代码段的SS:ESP和CS:EIP
	mov	word ptr ds:[ebx+TSS.regSs], g_TestStack1Selector
	mov	dword ptr ds:[ebx+TSS.regEsp], Stack_Len;初始化TSS的SS:ESP

	mov	word ptr ds:[ebx+TSS.regCs], g_TestCodeSelector
	mov	dword ptr ds:[ebx+TSS.regEip], _TestCodeBegin
	mov	dword ptr ds:[ebx+TSS.regEflags], IOPL1	;TSS的IOPL值
	mov	word ptr ds:[ebx+TSS.regLdtr], g_TestLdtSelector
;----------------------------------------------------------------------------
	;通过任务门转移到 TestCodeSeg-->_TestCodeBegin
	CALL32	g_TestTaskSelector, 0
DemoBegin 	Endp
;============================================================================
_DemoEnd		equ	$ - DemoCodeSeg
DemoEnd		Proc					;从1环返回

;----------------------------------------------------------------------------
	;打印一个字符串DemoTask!
	mov	ax, g_VideoSelector
	mov	es, ax

	mov	ax, g_DemoDataSelector
	mov	ds, ax
	cld

	mov	esi, offset SzDemoMessage
	mov	ecx, sizeof SzDemoMessage - 1
	mov	edi, 80 * 2 * 6 + 5 * 2			;5行5列

@@:	lodsb
	mov	ah, 0ch
	stosw
	loop	@b
;----------------------------------------------------------------------------
	mov	ax, cs
	and	al, 11b
	xor	cl, cl
	shl	al, 7
	rcl	cl, 1					;将特权级的高位移动过来
	add	cl, '0'

	sal	al, 1
	rcl	al, 1
	add	al, '0'
	mov	ah, 0ch
	shl	eax, 16
	mov	al, cl
	mov	ah, 0ch					;打印特权级
	stosd
;----------------------------------------------------------------------------
	Jmp32	g_CodeTempSelector, _GoToProtect	;返回实模式
DemoEnd 	Endp
DemoCodeSegLen		equ	$ - DemoCodeSeg
DemoCodeSeg	Ends
;============================================================================
DemoTssSeg	Segment use32				;演示任务TSS段
	DemoTss	TSS <0>
	byte	0ffh
DemoTssSegLen		equ	$ - DemoTssSeg
DemoTssSeg	Ends
;============================================================================
TestTssSeg	Segment use32				;测试任务TSS段
	TestTss	TSS <0>
IoMap	label	byte					;IO许可位图
TestTssSegLen		equ	$ - TestTssSeg
TestTssSeg	Ends
;============================================================================
	;16位段, 由实模式跳入
;============================================================================
g_Code16Seg	Segment	use16
_GoToProtect	Proc					;返回实模式
	mov	ax, NormalSelector
	mov	fs, ax					;规范选择子
	mov	es, ax
	mov	ds, ax
	mov	ss, ax
	clts						;清除任务标记

	mov	eax, cr0				;关PE位, 进入实模式
	and	al, 0feh
	mov	cr0, eax

	;刷新段选择子缓冲区, 退回实模式
	Jmp16	<seg StartCodeSeg >, < offset _RealProtect >
_GoToProtect 	Endp
;----------------------------------------------------------------------------
_ProtectEntry	Proc					;实模式跳入入口
	mov	ax, 0
	mov	ds, ax
	mov	es, ax
	mov	fs, ax
	mov	gs, ax					;置各选择子为NULL

	mov	ax, g_Stack0Selector
	mov	ss, ax
	mov	esp, Stack_Len				;初始化0环Ss:Esp
;----------------------------------------------------------------------------
	mov	ax, g_DemoTssSelector
	ltr	ax					;装载TSS任务寄存器

	;16位转32位代码段
	Jmp16	g_DemoCodeSelector, <_DemoBegin >
_ProtectEntry 	Endp
g_Code16Seg	Ends
;============================================================================
	;起始代码段初始化保护模式的各个结构, 然后跳入保护模式
;============================================================================
StartCodeSeg	Segment use16
_InitGdt	Proc	uses es				;初始化全局描述符表
	local	_Vidt:fword

	xor	eax, eax
	mov	ax, GdtSeg
	mov	es, ax					;es-->全局描述符表
;----------------------------------------------------------------------------
	shl	eax, 4
	mov	dword ptr es:[GDT_Ptr+2], eax		;初始化VGDT描述符
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, g_Code16Seg				;初始化十六位的代码段
	shl	eax, 4
	mov	word ptr es:[g_CodeTempDesc+2], ax	;段基址低位
	shr	eax, 16
	mov	byte ptr es:[g_CodeTempDesc+4], al	;段基址高地址低位
	mov	byte ptr es:[g_CodeTempDesc+7], ah	;段基址高地址高位
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, Stack0				;初始化0环堆栈段
	shl	eax, 4
	mov	word ptr es:[g_Stack0Desc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_Stack0Desc+4], al
	mov	byte ptr es:[g_Stack0Desc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, DemoCodeSeg				;初始化32位代码段
	shl	eax, 4
	mov	word ptr es:[g_DemoCodeSelector+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_DemoCodeSelector+4], al
	mov	byte ptr es:[g_DemoCodeSelector+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, DemoTssSeg				;初始化演示TSS段描述符
	shl	eax, 4
	mov	word ptr es:[g_DemoTssDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_DemoTssDesc+4], al
	mov	byte ptr es:[g_DemoTssDesc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, TestTssSeg				;初始化测试TSS段描述符
	shl	eax, 4
	mov	word ptr es:[g_TestTssDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_TestTssDesc+4], al
	mov	byte ptr es:[g_TestTssDesc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, Stack1				;初始化1环堆栈段
	shl	eax, 4
	mov	word ptr es:[g_TestStack1Desc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_TestStack1Desc+4], al
	mov	byte ptr es:[g_TestStack1Desc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, DemoDataSeg				;初始化Demo数据段
	shl	eax, 4
	mov	word ptr es:[g_DemoDataDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_DemoDataDesc+4], al
	mov	byte ptr es:[g_DemoDataDesc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, TestCodeSeg				;初始化测试代码段
	shl	eax, 4
	mov	word ptr es:[g_TestCodeDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_TestCodeDesc+4], al
	mov	byte ptr es:[g_TestCodeDesc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, TestTssSeg				;初始化测试代码别名段
	shl	eax, 4
	mov	word ptr es:[g_TestTssAliasDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_TestTssAliasDesc+4], al
	mov	byte ptr es:[g_TestTssAliasDesc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, DemoTssSeg				;初始化演示代码别名段
	shl	eax, 4
	mov	word ptr es:[g_DemoTssAliasDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_DemoTssAliasDesc+4], al
	mov	byte ptr es:[g_DemoTssAliasDesc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, GdtSeg				;初始化GDT别名段
	shl	eax, 4
	mov	word ptr es:[g_GdtAliasDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_GdtAliasDesc+4], al
	mov	byte ptr es:[g_GdtAliasDesc+7], ah
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, LdtTestSeg				;初始化测试代码段的LDT
	shl	eax, 4
	mov	word ptr es:[g_TestLdtDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[g_TestLdtDesc+4], al
	mov	byte ptr es:[g_TestLdtDesc+7], ah
;----------------------------------------------------------------------------
	sidt	fword ptr es:[_IDT_Ptr]			;保存IDT

	mov	word ptr ss:[_Vidt], IdtSegLen		;IDT长度
	mov	eax, IdtSeg
	shl	eax, 4
	mov	dword ptr ss:[_Vidt+2], eax

	lidt	fword ptr ss:[_Vidt]			;装载IDT
	lgdt	fword ptr es:[GDT_Ptr]			;装载GDT
;----------------------------------------------------------------------------
	ret
_InitGdt 	Endp
;----------------------------------------------------------------------------
_InitLdt	Proc	uses es

	mov	ax, LdtTestSeg
	mov	es, ax
;----------------------------------------------------------------------------
	xor	eax, eax
	mov	ax, TestDataSeg				;初始化测试代码段的数据段
	shl	eax, 4
	mov	word ptr es:[L_TestDataDesc+2], ax
	shr	eax, 16
	mov	byte ptr es:[L_TestDataDesc+4], al
	mov	byte ptr es:[L_TestDataDesc+7], ah
;----------------------------------------------------------------------------
	ret
_InitLdt 	Endp
;----------------------------------------------------------------------------
Jmain		Proc

	call	_InitGdt				;初始化GDT全局描述符
	call	_InitLdt				;初始化LDT局部描述符
;----------------------------------------------------------------------------
	mov	ax, GdtSeg
	mov	ds, ax

	mov	ds:[_RegSs], ss
	mov	ds:[_RegSp], sp				;保存SS:SP
	cli
	_EnableA20					;关中断开A20地址线
	mov	eax, cr0
	or	eax, 1
	mov	cr0, eax				;开启分段, 进入保护模式
;----------------------------------------------------------------------------
	Jmp16	g_CodeTempSelector, <offset _ProtectEntry>;跳入保护模式

Jmain 		Endp
;----------------------------------------------------------------------------
_RealProtect	Proc                                    ;返回保护模式

        mov     ax, GdtSeg
        mov     ds, ax
        lss	sp, dword ptr ds:[_RegSp]		;恢复SS:SP
        lidt	fword ptr ds:[_IDT_Ptr]			;恢复IDT

        _DisableA20                                     ;关A20地址线, 开中断
        sti
        mov     ax, 4c00h
        int     21h
_RealProtect	Endp
StartCodeSeg	Ends

End	Jmain

 

发表评论


Warning: Undefined variable $user_ID in /www/wwwroot/joenchen.com/wp-content/themes/agan/comments.php on line 66

您必须登录 才能进行评论。