;T10-5.ASM
;演示任务切换和任务内特权级变换
include 386SCD.ASM
.386P
;全局描述符表
GDTSEG SEGMENT PARA USE16
GDT LABEL BYTE
dummy descriptor <>
normal descriptor <0ffffh,0,0,atdw,0>
normal_sel=normal-gdt
effgdt label byte
demotss descriptor <demotsslen-1,demotssseg,,at386tss,>
demotss_sel=demotss-gdt
demoldtab descriptor <demoldtlen-1,demoldtseg,,atldt,>
demoldt_sel=demoldtab-gdt
;临时任务的任务状态段描述符
temptss descriptor <temptsslen-1,temptssseg,,at386tss+dpl2,>
temptss_sel=temptss-gdt
;临时任务代码段
tempcode descriptor <0ffffh,tempcodeseg,,atce,>
tempcode_sel=tempcode-gdt
;子程序代码段描述符
subr descriptor <subrlen-1,subrseg,,atce+d32,>
subr_sel=subr-gdt+rpl3
videobuff descriptor <0ffffh,0,0,0f00h+atdw+dpl3,0>
video_sel=videobuff-gdt
gdnum=($-effgdt)/(size descriptor)
gdtlen=$-gdt
gdtseg ends
;演示任务的任务状态段
DemoTSSSEG segment para use16
dd 0 ;链接字
dd DemoStack0LEN ;0级堆栈指针
dw DemoStack0_SEL,0
dd 0 ;1级堆栈指针
dw ?,0
dd DemoStack2LEN ;2级堆栈指针
DW Demostack2_sel,0
dd 0 ;cr3
dw demobegin,0 ;eip
dd 0 ;eflags
dd 0 ;eax
dd 0 ;ecx
dd 0 ;edx
dd 0 ;ebx
dd DemoStack2LEN ;esp
dd 0 ;ebp
dd 0 ;esi
dd 0B8000H ;edi
dw video_sel,0 ;es
dw DemoCode_sel,0 ;cs
dw DemoStack2_sel,0 ;ss
dw DemoData_sel,0 ;ds
dw ToDLDT_SEL,0 ;fs
dw ToTTSS_SEL,0 ;gs
dw DemoLDT_SEL,0 ;ldtr
dw 0
dw $+2 ;I/O许可位图指针
db 0ffh ;I/O许可位图结束字节
DemoTSSLEN=$
DemoTSSSEG ends
;演示任务的局部描述符表LDT
DemoLDTSEG segment para use16
demoldt label byte
demostack0 descriptor <demostack0len-1,demostack0seg,,atdw+d32,>
demostack0_sel=(demostack0-demoldt)+til
demostack2 descriptor <demostack2len-1,demostack2seg,,atdw+d32+dpl2,>
demostack2_sel=(demostack2-demoldt)+til+rpl2
;演示代码段描述符
democode descriptor <democodelen-1,democodeseg,,atce+d32+dpl2,>
democode_sel=(democode-demoldt)+til+rpl2
;演示数据段描述符
demodata descriptor <demodatalen-1,demodataseg,,atdw+d32+dpl3,>
demodata_sel=(demodata-demoldt)+til
;把LDT作为普通数据段描述的描述符(DPL=2)
todldt descriptor <demoldtlen-1,demoldtseg,,atdw+dpl2,>
todldt_sel=(todldt-demoldt)+til
;把tss作为普通数据段描述的描述符(DPL=2)
TOTTSS descriptor <temptsslen-1,temptssseg,,atdw+dpl2,>
tottss_sel=(tottss-demoldt)+til
demoLDNUM=($-demoldt)/(size descriptor)
;指向子程序subrb的调用门(dpl=3)
tosubr gate <subrb,subr_sel,0,at386cgat+dpl3,0>
tosubr_sel=(tosubr-demoldt)+til+rpl2
;指向临时任务temp的任务门(DPL=3)
totempt gate <0,temptss_sel,0,attaskgat+dpl3,0>
totempt_sel=(totempt-demoldt)+til
demoldtlen=$-demoldt
demoldtseg ends
;演示任务的0级堆栈
DemoStack0SEG segment para use32
demostack0len=1024
db demostack0len dup(0)
demostack0seg ends
DemoStack2SEG segment para use32
demostack2len=512
db demostack2len dup(0)
demostack2seg ends
;演示任务的数据段
DemoDataSEG segment para use32
message db 'Value=',0
demodatalen=$
demodataseg ends
subrseg segment para use32
assume cs:subrseg
subrb proc far
push ebp
mov ebp,esp
pushad
mov eax,[ebp+12]
mov esi,eax
mov ah,7
jmp short subr2
subr1: stosw
subr2: lodsb
or al,al
jnz subr1
mov edx,[ebp+16]
mov ecx,8
subr3: rol edx,4
mov al,dl
call htoasc
stosw
loop subr3
popad
pop ebp
ret 8
subrb endp
htoasc proc
and al,0fh
add al,90h
daa
adc al,40h
daa
ret
htoasc endp
subrlen=$
subrseg ends
DemoCodeSEG segment para use32
assume cs:DemoCodeSEG
DemoBegin:
mov fs:tosubr.dcount,2 ;?看不懂的地方2,这里的段寄存器为啥是fs
push dword ptr gs:temptask.treip ;?看不懂的地方3,这里的段寄存器为啥是gs
push offset Message
call32 tosubr_sel,0 ;这个子函数看得懂
assume ds:temptssseg
push gs
pop ds ;看不懂的地方4,为啥要push gs然后pop ds
mov ax,normal_sel
mov temptask.trds,ax
mov temptask.tres,ax
mov temptask.trfs,ax
mov temptask.trgs,ax
mov temptask.trss,ax
jump32 totempt_sel,0 ;看不懂的地方5,这里的totempt_sel选择子对应的是段temptssseg,而段temptssseg是个没赋初值的结构
;体,怎么跳转过去呢?
DemoCodeLEN=$
DemoCodeSEG ends
temptssseg segment para use16
temptask taskss <>
db 0ffh
temptsslen=$
temptssseg ends
tempcodeseg segment para use16
assume cs:tempcodeseg
Virtual:
mov BX,tempTSS_SEL
LTR BX
jump16 demotss_sel,0 ;这里进行了切换到任务DemoTSSSEG,因为EIP是demobegin,这里跳转到demobegin
toreal:
clts
mov eax,cr0
and eax,0fffffffeh
mov cr0,eax
jump16 <seg real>,<offset real>
tempcodelen=$
tempcodeseg ends
RDataSEG segment para use16
VGDTR PDESC <GDTLEN-1,>
SPVAR DW ?
SSVAR DW ?
RDataSEG ends
RCodeSEG segment para use16
assume cs:rcodeseg,ds:rdataseg,es:rdataseg ;看不懂的地方1,以前没见到过一个段同时和两个段寄存器对应的代码
start:
mov ax,Rdataseg
mov ds,ax
cld
call init_gdt
mov ax,DemoLDTSEG
mov fs,ax
mov cx,DemoLDNUM
mov SI,OFFSET DemoLDT
call init_ldt
mov ssvar,ss
mov spvar,sp
lgdt qword ptr vgdtr
cli
mov eax,cr0
or eax,1
mov cr0,eax
jump16 <tempCode_sel>,<offset virtual>
Real:
mov ax,RDataSEG
mov ds,ax
lss sp,dword ptr spvar
sti
mov ax,4c00h
int 21h
init_gdt proc near
push ds
mov ax,gdtseg
mov ds,ax
mov cx,gdnum
mov si,offset effgdt
initg: mov ax,[si].basel
movzx eax,ax
shl eax,4
shld edx,eax,16
mov [si].basel,ax
mov [si].basem,dl
mov [si].baseh,dh
add si,size descriptor
loop initg
pop ds
mov bx,16
mov ax,gdtseg
mul bx
mov word ptr vgdtr.base,ax
mov word ptr vgdtr.base+2,dx
ret
init_gdt endp
init_ldt proc
ildt: mov ax,fs:[si].basel
movzx eax,ax
SHL eax,4
shld edx,eax,16
mov fs:[si].basel,ax
mov fs:[si].basem,dl
mov fs:[si].baseh,dh
add si,size descriptor
loop ildt
ret
init_ldt endp
RCodeSEG ends
end start