📄 asm11.asm
字号:
REPT 256 ;对应256个入口
IF Count EQ 21h
Ent21H LABEL BYTE ;在第21H项处定义标号Ent21H
ENDIF
push bp
mov bp,Count ;置中断向量号到BP
jmp Process ;都转统一的处理程序
Count = Count+1
ENDM
Process: push bp ;保存BP
mov bp,sp ;堆栈指针送BP
push eax
push ebx ;保存EAX、EBX
;在V86堆栈顶形成返回点的现场
mov ax,VAllMem_Sel ;转载描述最低1M字节线性地址
mov ds,ax ; 空间的描述符选择子
xor eax,eax
mov ax,Psp ;修改在V86任务0级堆栈中保存
sub ax,3*2 ; 的3级堆栈的指针,减3个字
mov Psp,ax ; 即在栈顶空出3个字
xor ebx,ebx
mov bx,Pss ;使EBX指向V86堆栈顶
shl ebx,4
add ebx,eax
mov ax,Pip ;把保存在0级堆栈中的返回地址
mov WORD PTR [ebx],ax ;的偏移部分送V86堆栈
mov ax,Pcs
mov WORD PTR [ebx+2],ax ;段值部分送V86堆栈
mov ax,Pflag
mov WORD PTR [ebx+4],ax ;标志值送V86堆栈
;用对应的中断向量值代替返回地址
mov bx,[bp] ;取中断向量号
shl bx,2 ;乘4
mov ax,[bx] ;取实模式下对应中断向量的偏移
mov Pip,ax ;代替0级堆栈中的EIP
mov ax,[bx+2] ;取实模式下对应中断向量的段值
mov Pcs,ax ;代替0级堆栈中的CS
pop ebx ;恢复现场
pop eax
pop bp
pop bp
;从保护方式返回V86方式
;先转入对应的中断处理程序,再返回中断发生处
iretd
TPBegin ENDP
;----------------------------------------------------------------------------
TPCodeLen = $
TPCodeSeg ENDS
;============================================================================
;V86任务下的通用保护故障处理程序代码段
;----------------------------------------------------------------------------
GPCodeSeg SEGMENT PARA USE32
ASSUME CS:GPCodeSeg
;----------------------------------------------------------------------------
GPBegin PROC FAR
mov ax,V86Data_Sel
mov ds,ax
mov si,OFFSET GPErrMess
mov ax,Video_Sel
mov es,ax
mov di,0
mov ah,17h
mov cx,GPErrMessLen
cld
GNext: lodsb
stosw
loop GNext
add esp,4
mov ax,4c01h
JUMP16 TPCode_Sel,Ent21H
GPBegin ENDP
;----------------------------------------------------------------------------
GPCodeLen = $
GPCodeSeg ENDS
;============================================================================
;V86方式执行的8086程序段
V86CodeSeg SEGMENT PARA USE16
ASSUME CS:V86CodeSeg,DS:V86CodeSeg
Message DB 'V86 is OK!',0dh,0ah,24h
V86Begin PROC FAR
mov ah,9
mov dx,OFFSET Message
int 21h
mov ax,RCodeSeg
sub ax,GDTSeg
mov dx,OFFSET TSRLine+15
shr dx,4
add dx,ax
add dx,10h
mov ax,3100h
int 21h
V86Begin ENDP
V86CodeSeg ENDS
;============================================================================
TempTSSSeg SEGMENT PARA USE16 ;临时任务的TSS段
TSS <>
DB 0ffh ;I/O许可位图结束标志
TempTSSLen = $
TempTSSSeg ENDS
;============================================================================
TempCodeSeg SEGMENT PARA USE16 ;临时任务的代码段
ASSUME CS:TempCodeSeg
;----------------------------------------------------------------------------
Virtual PROC FAR
mov ax,Normal_Sel
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov ax,TempTSS_Sel ;装载TR
ltr ax
JUMP16 V86TSS_Sel,0 ;直接切换到演示任务
ToDos: clts
mov eax,cr0 ;准备返回实模式
and al,11111110b
mov cr0,eax
JUMP16 <SEG Real>,<OFFSET Real>
Virtual ENDP
;----------------------------------------------------------------------------
TempCodeSeg ENDS
;============================================================================
RDataSeg SEGMENT PARA USE16 ;实方式数据段
RDataSeg ENDS
;============================================================================
RCodeSeg SEGMENT PARA USE16
ASSUME CS:RCodeSeg,DS:RCodeSeg
;----------------------------------------------------------------------------
VGDTR PDesc <GDTLen-1,> ;GDT伪描述符
VIDTR PDesc <IDTLen-1,> ;IDT伪描述符
NORVIDTR PDesc <> ;用于保存原IDTR值
SPVar DW ? ;用于保存实方式下的SP
SSVar DW ? ;用于保存实方式下的SS
;----------------------------------------------------------------------------
Start PROC
mov ax,RCodeSeg
mov ds,ax
cld
call InitGDT ;初始化全局描述符表GDT
call InitIDT ;初始化中断描述符表IDT
mov ax,V86LDTSeg
mov fs,ax
mov cx,V86LDNum
mov si,OFFSET VLDT
call InitLDT
mov ax,IntFFLDTSeg
mov fs,ax
mov cx,IntFFLDNum
mov si,OFFSET FLDT
call InitLDT
mov SSVar,ss
mov SPVar,sp
lgdt QWORD PTR VGDTR ;装载GDTR并切换到保护方式
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,cs
mov ds,ax
lss sp,DWORD PTR SPVar ;又回到实方式
lidt QWORD PTR NORVIDTR
sti
mov ax,4c00h
int 21h
Start ENDP
;----------------------------------------------------------------------------
TSRLine LABEL BYTE
;----------------------------------------------------------------------------
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
;----------------------------------------------------------------------------
;入口参数:FS:SI=第一个要初始化的描述符,CX=要初始化的描述符数
;----------------------------------------------------------------------------
InitLDT PROC
mov ax,WORD PTR FS:[si].BaseL
movzx eax,ax
shl eax,4
shld edx,eax,16
mov WORD PTR fs:[si].BaseL,ax
mov BYTE PTR fs:[si].BaseM,dl
mov BYTE PTR fs:[si].BaseH,dh
add si,SIZE Desc
loop InitLDT
ret
InitLDT ENDP
;----------------------------------------------------------------------------
InitIDT PROC
push ds
mov ax,IDTSeg
mov ds,ax
mov cx,256-1
mov si,OFFSET IDT
mov ax,OFFSET TPBegin
IIDT1: cmp cx,256-1-13
jz IIDT2
mov [si],ax
IIDT2: add si,8
add ax,7
loop IIDT1
pop ds
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 + -