📄 asm9.asm
字号:
DB 11111011b ;端口40h--47h
DB 3 DUP(0ffh) ;端口48h--5fh
DB 11111101b ;端口60h--67h
DB 0 ;端口68h--6fh
DB 0ffh ;I/O许可位图结束标志
TestTSSLen = $
TestTSSSeg ENDS
;----------------------------------------------------------------------------
;测试任务的堆栈段
TestStackSeg SEGMENT PARA USE32
TestStackLen = 1024
DB TestStackLen DUP(0)
TestStackSeg ENDS
;----------------------------------------------------------------------------
;测试任务的代码段
TestCodeSeg SEGMENT PARA USE32
ASSUME CS:TestCodeSeg
;----------------------------------------------------------------------------
Test3Begin PROC FAR
cli ;I/O敏感指令
clts ;特权指令
iretd
jmp Test3Begin
Test3Begin ENDP
;----------------------------------------------------------------------------
TestBegin PROC FAR
mov al,0b6h ;使扬声器发出一长声
out 43h,al
mov al,2
out 42h,al
mov al,34h
out 42h,al
in al,61h
mov ah,al
or al,3
out 61h,al
mov ecx,1234567h
loop $
mov al,ah
out 61h,al
iretd
jmp TestBegin
TestBegin ENDP
;----------------------------------------------------------------------------
TestCodeLen = $
TestCodeSeg ENDS
;----------------------------------------------------------------------------
;演示任务TSS段
DemoTSSSeg SEGMENT PARA USE16
DemoTaskSS TSS <>
DB 0ffh ;I/O许可位图结束字节
DemoTSSLen = $
DemoTSSSeg ENDS
;----------------------------------------------------------------------------
;演示任务的堆栈段
DemoStackSeg SEGMENT PARA USE32
DemoStackLen = 1024
DB DemoStackLen DUP(0)
DemoStackSeg ENDS
;----------------------------------------------------------------------------
;演示任务的代码段
DemoCodeSeg SEGMENT PARA USE32
ASSUME CS:DemoCodeSeg
;----------------------------------------------------------------------------
DemoBegin PROC FAR
mov ax,ToTestTSS_Sel
mov ds,ax
mov ebx,OFFSET TestTaskSS
;把测试任务1的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS
mov WORD PTR [ebx].TRSS,Test1Stack_Sel
mov DWORD PTR [ebx].TRESP,TestStackLen
mov WORD PTR [ebx].TRCS,Test1Code_Sel
mov DWORD PTR [ebx].TREIP,OFFSET TestBegin
mov DWORD PTR [ebx].TREFLAG,IOPL1
;通过任务门调用测试任务
CALL32 Test_Sel,0
;把测试任务2的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS
mov WORD PTR [ebx].TRSS,Test2Stack_Sel
mov DWORD PTR [ebx].TRESP,TestStackLen
mov WORD PTR [ebx].TRCS,Test2Code_Sel
mov DWORD PTR [ebx].TREIP,OFFSET TestBegin
mov DWORD PTR [ebx].TREFLAG,IOPL1
;通过任务门调用测试任务
CALL32 Test_Sel,0
;把测试任务TSS描述符内的属性置为"可用"
mov ax,ToGDT_Sel
mov fs,ax
mov fs:TestTSS.Attributes,AT386TSS
;把测试任务3的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS
mov WORD PTR [ebx].TRSS,Test3Stack_Sel
mov DWORD PTR [ebx].TRESP,TestStackLen
mov WORD PTR [ebx].TRCS,Test3Code_Sel
mov DWORD PTR [ebx].TREIP,OFFSET Test3Begin
mov DWORD PTR [ebx].TREFLAG,IOPL2
;通过任务门调用测试任务
CALL32 Test_Sel,0
;把测试任务TSS描述符内的属性置为"可用"
mov ax,ToGDT_Sel
mov fs,ax
mov fs:TestTSS.Attributes,AT386TSS
;把测试任务4的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS
mov WORD PTR [ebx].TRSS,Test3Stack_Sel
mov DWORD PTR [ebx].TRESP,TestStackLen
mov WORD PTR [ebx].TRCS,Test3Code_Sel
mov DWORD PTR [ebx].TREIP,OFFSET Test3Begin
mov DWORD PTR [ebx].TREFLAG,IOPL3
;通过任务门调用测试任务
CALL32 Test_Sel,0
JUMP32 TempCode_Sel,<OFFSET ToDOS>
DemoBegin ENDP
;----------------------------------------------------------------------------
DemoCodeLen = $
DemoCodeSeg ENDS
;----------------------------------------------------------------------------
TempCodeSeg SEGMENT PARA USE16 ;演示任务的临时代码段
ASSUME CS:TempCodeSeg
;----------------------------------------------------------------------------
Virtual PROC FAR
;置数据段寄存器为空
mov ax,0
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
;置堆栈指针
mov ax,DemoStack_Sel
mov ss,ax
mov esp,DemoStackLen
;置任务寄存器
mov ax,DemoTSS_Sel
ltr ax
;转演示代码段
JUMP16 DemoCode_Sel,DemoBegin
ToDOS: clts
mov ax,Normal_Sel
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov eax,cr0
and al,11111110b
mov cr0,eax
JUMP16 <SEG Real>,<OFFSET Real>
Virtual ENDP
;----------------------------------------------------------------------------
TempCodeSeg ENDS
;============================================================================
RDataSeg SEGMENT PARA USE16 ;实方式数据段
VGDTR PDesc <GDTLen-1,> ;GDT伪描述符
VIDTR PDesc <IDTLen-1,> ;IDT伪描述符
NORVIDTR PDesc <3ffh,> ;用于保存原IDTR值
SPVar DW ? ;用于保存实方式下的SP
SSVar DW ? ;用于保存实方式下的SS
RDataSeg ENDS
;----------------------------------------------------------------------------
RCodeSeg SEGMENT PARA USE16 ;实方式代码段
ASSUME CS:RCodeSeg,DS:RDataSeg
;----------------------------------------------------------------------------
Start PROC
mov ax,RDataSeg
mov ds,ax
cld
call InitGDT ;初始化全局描述符表GDT
call InitIDT ;初始化中断描述符表IDT
lgdt QWORD PTR VGDTR ;装载GDTR
mov SSVar,ss ;保存堆栈指针
mov SPVar,sp
sidt QWORD PTR NORVIDTR ;保存IDTR
cli ;关中断
lidt QWORD PTR VIDTR ;装载IDTR
mov eax,cr0
or al,1
mov cr0,eax
JUMP16 <TempCode_Sel>,<OFFSET Virtual>
Real: mov ax,RDataSeg
mov ds,ax
lss sp,DWORD PTR SPVar ;又回到实方式
lidt QWORD PTR NORVIDTR
sti
mov ax,4c00h
int 21h
Start ENDP
;----------------------------------------------------------------------------
InitGDT PROC
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 WORD PTR [si].BaseL,ax
mov BYTE PTR [si].BaseM,dl
mov BYTE PTR [si].BaseH,dh
add si,SIZE Desc
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
InitGDT ENDP
;----------------------------------------------------------------------------
InitIDT PROC
mov bx,16
mov ax,IDTSeg
mul bx
mov WORD PTR VIDTR.Base,ax
mov WORD PTR VIDTR.Base+2,dx
ret
InitIDT ENDP
;----------------------------------------------------------------------------
RCodeSeg ENDS
END Start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -