码迷,mamicode.com
首页 > 编程语言 > 详细

《80X86汇编语言程序设计教程》十五 任务切换实例

时间:2017-11-19 19:50:15      阅读:269      评论:0      收藏:0      [点我收藏+]

标签:val   方式   实现   导致   保护模式   目标   att   状态   tor   

1、  理论知识参考"《80X86汇编语言程序设计教程》十二 任务状态段、控制门和控制转移",演示内容:直接通过TSS段的任务切换、通过任务门的任务切换、任务内特权级的变换及参数传递。实现的逻辑功能是:从Temp任务切换到Demo任务以后显示原任务(Temp)的挂起点EIP的值。

 

 

2、  源代码

  “386scd.asm”不再贴上来。参考"《80X86汇编语言程序设计教程》十三 任务内无特权级变换转移实例",演示代码如下:

 

  1 ;DosTest.Asm
  2 ;任务切换实例
  3 ;逻辑功能:从Temp任务切换到Demo任务以后显示原任务(Temp)的挂起点EIP的值
  4 
  5 
  6     include    386scd.asm                    ;文件386.scd含有有关结构、宏指令和符号常量定义
  7     .386p
  8 
  9 ;------------------------------------------
 10 ;全局描述符表GDT
 11 GDTSeg    segment    para    use16
 12     GDT        label    byte
 13     ;空描述符
 14     dummy      DESCRIPTOR<>
 15     
 16     ;规范数据段描述符,存在的可读写数据段
 17     Normal     DESCRIPTOR<0ffffh,0,0,ATDW,0>
 18     Normal_Sel = Normal - GDT
 19     EFFGDT     label    byte
 20     
 21     ;演示任务状态段TSS描述符(16位段,DPL = 0,RPL = 0)
 22     DemoTSS    DESCRIPTOR<DemoTSSLen -1,DemoTSSSeg,,AT386TSS,>
 23     DemoTSS_Sel = DemoTSS - GDT
 24     
 25     ;演示任务LDT段描述符(16位段,DPL = 0,RPL = 0)
 26     DemoLDTab     DESCRIPTOR<DemoLDTLen-1,DemoLDTSeg,,ATLDT,>
 27     DemoLDT_Sel = DemoLDTab - GDT
 28     
 29     ;临时任务任务状态TSS描述符(16位段,DPL = 2,RPL = 0)
 30     TempTSS DESCRIPTOR<TempTSSLen - 1,TempTSSSeg,,AT386TSS + DPL2,>
 31     TempTSS_Sel = TempTSS - GDT
 32     
 33     ;临时任务代码段描述符(16位段,DPL = 0,RPL = 0)
 34     TempCode     DESCRIPTOR<0ffffh,TempCodeSeg,,ATCE,>
 35     TempCode_Sel = TempCode - GDT
 36     
 37     ;子程序代码段描述符(32位段,DPL = 0,RPL = 3)
 38     SubR     DESCRIPTOR<SubRLen - 1,SubRSeg,,ATCE + D32,>
 39     SubR_Sel = SubR - GDT + RPL3
 40     
 41     ;视频缓冲区段描述符,段界限0fffffh(16位段,DPL = 3,RPL = 0)
 42     VideoBuff    DESCRIPTOR<0ffffh,0,0,0f00h + ATDW + DPL3,0>
 43     Video_Sel = VideoBuff - GDT
 44     
 45     GDTNum = ($ - EFFGDT)/(size DESCRIPTOR)
 46         
 47     ;指向演示任务Demo的任务门(DPL = 3,RPL = 0)
 48     ;ToDemoT    GATE<0,DemoTSS_Sel,0,ATTASKGAT + DPL3,0>
 49     ;ToDemoT_Sel = (ToDemoT - GDT) + TIL
 50     
 51     GDTLen = $ - GDT
 52 GDTSeg    ends
 53 
 54 ;------------------------------------------
 55 ;演示任务局部描述符表LDT
 56 DemoLDTSeg    segment    para    use16
 57     DemoLDT    label    byte
 58     
 59     ;0级堆栈段描述符(32位段,DPL = 0,RPL = 0)
 60     DemoStack0     DESCRIPTOR<DemoStack0Len - 1,DemoStack0Seg,,ATDW + D32,>
 61     DemoStack0_Sel = (DemoStack0 - DemoLDT) + TIL
 62     
 63     ;2级堆栈段描述符(32位段,DPL = 2,RPL = 2)
 64     DemoStack2     DESCRIPTOR<DemoStack2Len - 1,DemoStack2Seg,,ATDW + D32 + DPL2,>
 65     DemoStack2_Sel = (DemoStack2 - DemoLDT) + TIL + RPL2
 66     
 67     ;演示任务代码段描述符(32位段,DPL = 2,RPL = 2)
 68     DemoCode     DESCRIPTOR<DemoCodeLen - 1,DemoCodeSeg,,ATCE + D32 + DPL2,>
 69     DemoCode_Sel = (DemoCode - DemoLDT) + TIL + RPL2
 70     
 71     ;演示任务数据段描述符(32位段,DPL = 3,RPL = 0)
 72     DemoData     DESCRIPTOR<DemoDataLen - 1,DemoDataSeg,,ATDW + D32 + DPL3,>
 73     DemoData_Sel = (DemoData - DemoLDT) + TIL
 74     
 75     ;把演示任务LDT作为普通数据段描述的描述符(16位段,DPL = 2,RPL = 0)
 76     ToDLDT     DESCRIPTOR<DemoLDTLen - 1,DemoLDTSeg,,ATDW + DPL2,>
 77     ToDLDT_Sel = (ToDLDT - DemoLDT) + TIL
 78     
 79     ;把临时任务TSS作为普通数据段描述的描述符(16位段,DPL = 2,RPL = 0)
 80     ToTTSS     DESCRIPTOR<TempTSSLen - 1,TempTSSSeg,,ATDW + DPL2,>
 81     ToTTSS_Sel = (ToTTSS - DemoLDT) + TIL
 82     
 83     ;LDT含非门描述符个数
 84     DemoLDTNum = ($ - DemoLDT)/(size DESCRIPTOR)
 85     
 86     ;指向子程序SubRB的调用门(DPL = 3,RPL = 2)
 87     ToSubR     GATE<low offset SubRB,SubR_Sel,0,AT386CGAT + DPL3,0>
 88     ToSubR_Sel = (ToSubR - DemoLDT) + TIL + RPL2
 89     
 90     ;指向临时任务Temp的任务门(DPL = 3,RPL = 0)
 91     ToTempT     GATE<0,TempTSS_Sel,0,ATTASKGAT + DPL3,0>
 92     ToTempT_Sel = (ToTempT - DemoLDT) + TIL
 93     
 94     ;LDT字节长度
 95     DemoLDTLen = $ - DemoLDT
 96 DemoLDTSeg    ends
 97 
 98 
 99 ;------------------------------------------
100 ;演示任务任务状态段(TSS)
101 DemoTSSSeg    segment    para    use16
102     DTSS    TASKSS<>
103             db    0ffh                    ;IO许可位结束标志
104     DemoTSSLen = $ - DemoTSSSeg
105 DemoTSSSeg    ends
106 
107 
108 ;------------------------------------------
109 ;临时任务的任务状态段(TSS)
110 TempTSSSeg    segment    para    use16
111     TempTask    TASKSS<>
112                 db    0ffh
113     TempTSSLen = $ - TempTSSSeg
114 TempTSSSeg    ends
115 
116 ;------------------------------------------
117 ;演示任务0级堆栈段(32位段)
118 DemoStack0Seg    segment    para    use32
119     DemoStack0Len = 1024
120     db    DemoStack0Len dup(0)
121 DemoStack0Seg    ends
122 
123 
124 ;------------------------------------------
125 ;演示任务2级堆栈段(32位段)
126 DemoStack2Seg    segment    para    use32
127     DemoStack2Len = 512
128     db    DemoStack2Len dup(0)
129 DemoStack2Seg    ends
130 
131 ;------------------------------------------
132 ;演示任务数据段(32位段)
133 DemoDataSeg    segment    para    use32
134     message        db    Value = ,0
135     DemoDataLen = $ - DemoDataSeg
136 DemoDataSeg    ends
137 
138 ;------------------------------------------
139 ;子程序代码段(32位段)
140 SubRSeg    segment    para    use32
141     assume    cs:SubRSeg
142 ;从堆栈中取出参数显示
143 SubRB    proc    far
144     push       ebp
145     mov        ebp,esp
146     pushad
147     ;从堆栈(0级)中取提示信息串偏移
148     mov        eax,[ebp + 12]
149     mov        esi,eax
150     mov        ah,7
151     jmp        short SubR2
152 SubR1:
153     stosw
154 SubR2:
155     lodsb
156     or         al,al
157     jnz        SubR1
158     ;从堆栈(0级)中取显示值
159     mov        edx,[ebp + 16]
160     mov        ecx,8
161 SubR3:
162     rol        edx,4
163     mov        al,dl
164     call       HTOASC
165     stosw
166     loop       SubR3
167     popad
168     pop        ebp
169     ret        8
170 SubRB    endp
171 
172 HTOASC    proc
173     and        al,0fh
174     add        al,90h
175     daa
176     adc        al,40h
177     daa
178     ret
179 HTOASC endp
180 
181     SubRLen = $ - SubRSeg
182     
183 SubRSeg    ends
184 
185 ;------------------------------------------
186 ;演示任务的代码段(32位段)
187 DemoCodeSeg    segment    para    use32
188     assume    cs:DemoCodeSeg
189 DemoBegin:
190     ;把要复制的参数个数置入调用门
191     mov        fs:ToSubR.Dcount,2
192     ;向堆栈(2级)中压入参数
193     mov        dword ptr gs:TempTask.TREIP,offset ToReal
194     push       dword ptr gs:TempTask.TREIP
195     push       offset message
196     ;通过调用门调用子程序SubRB
197     CALL32     ToSubR_Sel,0
198     ;把指向规范数据段描述符的选择子填入临时任务TSS
199     assume     ds:TempTSSSeg
200     push       gs
201     pop        ds
202     mov        ax,Normal_Sel
203     mov        TempTask.TRDS,ax
204     mov        TempTask.TRES,ax
205     mov        TempTask.TRFS,ax
206     mov        TempTask.TRGS,ax
207     mov        TempTask.TRSS,ax
208     ;通过任务切换到临时任务
209     JUMP32     ToTempT_Sel,0
210     DemoCodeLen = $ - DemoCodeSeg
211 DemoCodeSeg    ends
212 
213 ;------------------------------------------
214 ;临时代码段(16位段,0级)
215 TempCodeSeg    segment    para    use16
216     assume    cs:TempCodeSeg
217 Virtual:
218     ;装载TR
219     mov        bx,TempTSS_Sel
220     ltr        bx
221     ;直接切换到演示任务
222     ;JUMP16    ToDemoT_Sel,0
223     JUMP16     DemoTSS_Sel,0
224 ToReal:
225     ;准备切换回实模式
226     clts    ;清任务切换标志
227     ;
228     mov        eax,cr0
229     and        ax,0fffeh
230     mov        cr0,eax
231     JUMP16     <seg Real>,<offset Real>
232     TempCodeLen = $ - TempCodeSeg
233 TempCodeSeg    ends
234 
235 
236 ;------------------------------------------
237 ;实模式下的数据段
238 RDataSeg    segment    para    use16
239     VGDTR    PDESC<GDTLen - 1,>
240     SPVAR    dw    ?
241     SSVAR    dw    ?
242 RDataSeg    ends
243 ;------------------------------------------
244 ;实模式下的代码段
245 RCodeSeg    segment    para    use16
246     assume    cs:RCodeSeg,ds:RDataSeg,es:RDataSeg
247 start:
248     mov        ax,RDataSeg
249     mov        ds,ax
250     cld
251     ;初始化GDT
252     call       INIT_GDT
253     ;初始化演示任务LDT
254     mov        ax,DemoLDTSeg
255     mov        fs,ax
256     mov        si,offset DemoLDT
257     mov        cx,DemoLDTNum
258     call       INIT_LDT
259     ;初始化TSS
260     call       INIT_TSS
261     ;实模式堆栈保护
262     mov        SSVAR,ss
263     mov        SPVAR,sp
264     ;装载GDTR和切换到保护模式
265     lgdt       fword ptr VGDTR
266     cli
267     mov        eax,cr0
268     or         eax,1
269     mov        cr0,eax
270     JUMP16     TempCode_Sel,<offset Virtual>
271 Real:
272     ;又回到实模式
273     mov        ax,RDataSeg
274     mov        ds,ax
275     lss        sp,dword ptr SPVAR
276     sti
277     mov        ax,0700h
278     int        21h
279     mov        ax,4c00h
280     int        21h
281 ;------------------------------------------
282 ;初始化全局描述符表的子程序
283 ;(1)把定义时预置的段值转换成32位段基地址并置入描述符内相应字段
284 ;(2)初始化为GDTR准备的伪描述符
285 INIT_GDT    proc    near
286     push    ds
287     mov        ax,GDTSeg
288     mov        ds,ax
289     mov        cx,GDTNum                     ;初始化描述符的个数
290     mov        si,offset EFFGDT              ;开始偏移
291     assume     si:ptr DESCRIPTOR
292 INITG:
293     mov        ax,[si].BaseL                  ;取出预置的段值
294     movzx      eax,ax                         ;扩展到32位
295     shl        eax,4
296     shld       edx,eax,16                     ;分解到2个16位寄存器
297     mov        [si].BaseL,ax                  ;置入描述符相应字段
298     mov        [si].BaseM,dl
299     mov        [si].BaseH,dh
300     add        si,size DESCRIPTOR             ;调整到下一个描述符
301     loop       INITG
302     assume     si:nothing
303     pop        ds
304     ;
305     mov        bx,16                          ;初始化为GDTR准备的伪描述符
306     mov        ax,GDTSeg
307     mul        bx
308     mov        word ptr VGDTR.Base,ax
309     mov        word ptr VGDTR.Base + 2,dx
310     ret
311 INIT_GDT endp
312 ;------------------------------------------
313 ;初始化演示任务局部描述符表的子程序
314 ;把定义时预置的段值转换成32位段基地址并置入描述符内的相应字段
315 ;入口参数:FS:SI = 第一个要初始化的描述符
316 ;           CX = 要初始化的描述符个数
317 INIT_LDT    proc
318     assume    si:ptr DESCRIPTOR
319 ILDT:
320     mov        ax,fs:[si].BaseL
321     movzx      eax,ax
322     shl        eax,4
323     shld       edx,eax,16
324     mov        fs:[si].BaseL,ax
325     mov        fs:[si].BaseM,dl
326     mov        fs:[si].BaseH,dh
327     add        si,size DESCRIPTOR
328     loop       ILDT
329     assume     si:nothing
330     ret
331 INIT_LDT endp
332 ;------------------------------------------
333 ;初始化TSS段子程序
334 INIT_TSS    proc
335     mov        ax,DemoTSSSeg
336     mov        fs,ax
337     mov        si,offset DTSS
338     assume     si:ptr TASKSS
339     mov        fs:[si].TRLink,0                ;链接字 = 0
340     mov        fs:[si].TRESP0,DemoStack0Len    ;0级堆栈指针
341     mov        fs:[si].TRSS0,DemoStack0_Sel
342     mov        fs:[si].TRESP2,DemoStack2Len    ;2级堆栈指针
343     mov        fs:[si].TRSS2,DemoStack2_Sel
344     mov        fs:[si].TRESP,DemoStack2Len     ;当前使用2级堆栈
345     mov        fs:[si].TRSS,DemoStack2_Sel
346     mov        fs:[si].TRCR3,0                 ;CR3 = 0
347     mov        fs:[si].TREDI,0b8000h           ;ES:EDI指向视频输出缓冲区
348     mov        fs:[si].TRES,Video_Sel
349     mov        fs:[si].TREIP,offset DemoBegin  ;CS:EIP指向演示代码段起始位置
350     mov        fs:[si].TRCS,DemoCode_Sel
351     mov        fs:[si].TRDS,DemoData_Sel       ;DS指向演示任务数据段
352     mov        fs:[si].TRFS,ToDLDT_Sel         ;FS指向演示任务LDT(被当成数据段)
353     mov        fs:[si].TRGS,ToTTSS_Sel         ;GS指向临时任务TSS(被当成数据段)
354     mov        fs:[si].TRLDT,DemoLDT_Sel       ;演示任务LDTR
355     assume     si:nothing
356     ret
357 INIT_TSS endp
358 RCodeSeg    ends
359     end        start    

 

 

3、  源代码说明

  依然存在的一些类似问题,要么直接copy这里的代码,要么对比原书去找它们了,不重要。须注意的是在引用结构的时候这里采用了一种新的形式。

 

 

4、  输出

技术分享图片 

 

 

5、  测试说明

  1)  从Temp任务直接通过TSS切换到Dome任务

    LTR指令装载Temp任务的TSS并刷新高速缓冲区,以指示当前任务。Temp任务采用段间JMP指令进行任务切换:CPL = DPL = 0且目标TSS指示的是一个可用任务。这里有个很纠结的地方,切换任务以后,Temp任务的现场的确被保存了,只不过EIP寄存器都被初始化为0,导致系统奔溃:

技术分享图片 

    而且输出如下:

 技术分享图片

    从输出来看,EIP的确被初始化为0了,为什么是没有保存现场而是被初始化为0呢?因为我在JMP前强行给EIP赋值过,测试发现输出还是0。我测试自己电脑的CPU是686,不知道是不是CPU对JMP切换任务已经更换了策略,还是说有什么潜在的问题没有发现,暂时不得而知,总之,我尝试了各种方法,包括使用任务门、修改Temp的TSS任务为忙的TSS,这些尝试都是导致的系统直接奔溃。

  2)  从Dome任务通过任务门切换到Temp任务

    采用段间JMP,通过任务门切换回Temp任务:source.CPL(=2)<=gate.DPL(=3)且source.RPL(=0)<=gate.RPL(=0)所以成功进入任务门。进入门以后不再对权限等级进行保护检测(可以切换到目标任务的任何权限等级),由于目标任务可用,则直接实行了切换。由于上述毛病的存在,我这这里强势设置了一下EIP,使用的语句是“mov  dword ptr gs:TempTask.TREIP,offset ToReal”。

  3)  演示任务内特权级变换和堆栈传递参数

    采用段间CALL,通过调用门“ToSunR”调用子程序SubR。由于有权限等级的切换,栈也进行了切换。首先压入参数,须注意,压入时须保证CPL<=DPL且RPL<=DPL,栈是一种存储描述符。同时,注意调用门中Dcount字段,这个字段是压入参数的双字数目,这里压入了2个双字,所以设置为2。进入门的保护检测不再赘述。执行子程序时注意堆栈平衡。其它的没什么好说的。

  4)  别名技术

    在为了把调用门“ToSunR”中的Dcount字段设置为2时,使用了数据段描述符“ToDLDT”描述门所在演示任务的LDT段;此外在修改Temp任务的TSS时,也将其视普通的数据段。对同一内存段使用不同的解释方式,就是别名技术,这个不见得多么高深。

 

《80X86汇编语言程序设计教程》十五 任务切换实例

标签:val   方式   实现   导致   保护模式   目标   att   状态   tor   

原文地址:http://www.cnblogs.com/SChivas/p/7860660.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!