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

关于这个任务切换可以通过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位段切换到实模式, 然后搞定. 程序退出!

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

        TaskSwitching.rar

  
 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
;============================================================================
	;演示保护模式下的任务切换
	;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	"Demo 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