📄 pmstart8.asm
字号:
mov al,byte ptr [si]
mov dx,0c408h ;自8255A的口输出
out dx,al
mov al,byte ptr bz ;使相应的数码管亮
mov dx,0c409h
out dx,al
push cx ;延时,控制七段数码管相临两个数字显示之间的间隔
mov cx,3
delay11: push cx
mov cx,0ffffh
delay12: loop delay12
pop cx
loop delay11
pop cx
mov al,0 ;数码管清零,防止前后两次显示的数字重叠
mov dx,0c409h
out dx,al
mov bh,byte ptr bz
shr bh,1
jnz lll
loop loop2 ;循环延时
mov ax,word ptr [di]
cmp ah,09
jnz set
cmp al,09
jnz set
mov ax,0000
mov [di],al
mov [di+1],ah
jmp loop1
set: mov dx,0c40ah ;读8255C口
in al,dx
test al,08h
jne returnb ;K3=1返回SysCodeSeg
mov ax,word ptr [di]
inc al
aaa
mov [di],al ;al为十位
mov [di+1],ah ;ah中为个位
jmp loop1
returnb: pop gs
pop fs
pop es
pop ds
popad
JUMP16 SysTssSel,0
jmp taskb
TaskBCodeLen=$
TaskBCodeSeg ends
;-----------------------------------------------------------
;主任务状态段
SysTssSeg segment para use16
SysTaskSS TASKSS < >
db 0ffh
SysTssLen=$
SysTssSeg ends
;------------------------------------------
;主任务堆栈段
SysStack0Seg SEGMENT PARA USE16 ;0级堆栈
SysStack0_Pointer=1024
DB SysStack0_Pointer DUP(0)
SysStack0Len=$
SysStack0Seg ENDS
;-----------------
;主任务数据段
SysDataSeg segment para use16
hipm db ' Now it is in protected mode! ',0
inputpin db ' If K0=1, return to real mode. '
db ' If K1=1, go to TaskA. '
db ' If K2=1, go to TaskB, '
db ' If K3=1, back from TaskA or TaskB. ',0
endpm db ' Exit the protected mode! ' ,0
backapm db ' Back from TaskA! ',0
backbpm db ' Back from TaskB! ',0
SysDataSeg ends
;--------------------
;主任务代码段
SysCodeSeg segment para use16
assume cs:SysCodeSeg,ds:SysDataSeg
do_pm: mov ax,SysLdtSel
lldt ax
mov ax,SysStack0Sel ;;;;;;;;;;;;;;
mov ss,ax
mov sp,offset SysStack0Len ;;;;;;;;;;;;;;;
mov ax,ToSysTssSel
mov gs,ax ;把主任务LDT选择子填入TSS
mov WORD PTR gs:SysTaskSS.TRLDT,SysLdtSel
mov ax,SysTssSel
ltr ax
mov ax,SysDataSel
mov ds,ax
mov fs,ax
mov gs,ax
mov ax,VideoSel
mov es,ax
lea si,hipm ;输出字符串,提示已经进入保护模式
mov di,160*1
INT 0FEh
lea si,inputpin
mov di,160*3
INT 0FEh
mov dx,0c40bh ;设置8255控制字
mov al,89h
out dx,al
testkey:
mov dx,0c40ah ;读8255C口
in al,dx
test al,01h
jne exit ;K0=1则转exit
test al,02h
jne totaska ;K1=1则转TaskA
test al,04h
jne totaskb ;K2=1则转TaskB
jmp testkey
exit: lea si,endpm
mov di,160*11
INT 0FEh
JUMP16 TempCodeSel,<OFFSET ToReal>
totaska:JUMP16 TaskATssSel,0
clts
lea si,backapm
mov di,160*7
INT 0FEh
jmp testkey
totaskb: JUMP16 TaskBTssSel,0
clts
lea si,backbpm
mov di,160*9
INT 0FEh
jmp testkey
SysCodeLen=$
SysCodeSeg ends
;---------------------------
;临时代码段
TempCodeSeg segment para use16
assume cs: TempCodeSeg
Virtual:
JUMP16 SysCodeSel,<OFFSET do_pm>
ToReal:
mov ax,NormalSel
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov eax,cr0 ; 退出保护方式。
and eax,0fffffffeh
mov cr0,eax
jmp FAR ptr Real
TempCodeSeg ends
;----------------------------------------------------
;实方式下的数据段
RDataSeg segment para use16
V_GDTR PDESC <GdtLen-1,> ; 全局描述符表。
V_IDTR PDESC <IdtLen-1,> ; 中断描述符表。
RealIdtr PDESC <3FFH,0> ; 实方式下,中断表,0:0处。
SP_VALUE DW ?
SS_VALUE DW ?
IMASKREGV db ?
Mes1 DB 0DH,0AH, "PRESS ANY KEY TO EXIT!"
Mes1Len=$-Mes1
RDataSeg ends
;-------------------------------------------------------
;实方式下的代码段
RCodeSeg segment para use16
assume cs:RCodeSeg,ds:RDataSeg
Start:
mov ax,RDataSeg
mov ds,ax
mov es,ax
mov ah,0 ;清屏
mov al,03H
INT 10H
cld
PUSH DS
; 初始化全局描述符表GDT
CALL INIT_GDT
; 初始化中断描述符表IDT
CALL INIT_IDT
mov ax,SysLdtSeg
mov fs,ax
mov cx,SysLdtNum
mov si,OFFSET syldt
CALL INIT_LDT
mov ax,TaskALdtSeg
mov fs,ax
mov cx,TaskALdtNum
mov si,OFFSET taldt
CALL INIT_LDT
mov ax,TaskBLdtSeg
mov fs,ax
mov cx,TaskBLdtNum
mov si,OFFSET tbldt
CALL INIT_LDT
POP DS
MOV SP_VALUE,SP
MOV SS_VALUE,SS
;为了回到实方式后,恢复原IDTR之内容,先保存IDTR
SIDT QWORD PTR RealIdtr
in al,21h
mov IMASKREGV,al
LGDT QWORD PTR V_GDTR ; 装载GDTR
cli
LIDT V_Idtr ;装载中断描述符表寄存器IDTR
CALL EA20
MOV EAX,CR0
OR EAX,1
MOV CR0,EAX ; 启动保护方式
JUMP16 TempCodeSel,<OFFSET Virtual> ; 实方式下预取。
Real: CALL DA20
mov ax,RDataSeg
mov ds,ax
LSS SP,DWORD PTR SP_VALUE ; 恢复实方式下的堆栈。
LIDT RealIdtr
mov al,IMASKREGV
out 21h,al
sti
MOV AX,RDataSeg
MOV ES,AX
LEA BP,MES1
MOV DX,1700H
MOV BH,0
MOV CX,MES1Len
MOV AL,0
MOV BL,0D2H
MOV AH,13H
INT 10H ; 提示退出信息。
MOV AH,0
INT 16H
MOV AH,6
MOV AL,0
MOV BH,7 ; f & b Color
MOV CX,0
MOV DX,184FH
INT 10H ; 清屏,恢复原屏幕。
MOV AX,4C00H
INT 21H
;----------------------------------------------------------------------------
INIT_GDT proc near
push ds
ASSUME DS:GdtSeg
mov ax,GdtSeg
mov ds,ax
mov cx,GdtNum
lea si,effgdt
Inittg:
mov ax,[si].BASEL
MOV BX,16
MUL BX
mov [si].BASEL,ax
mov [si].BASEM,dl
mov [si].BASEH,dh
add si,size DESC
loop Inittg
ASSUME DS:RDataSeg
pop ds
mov bx,16
mov ax,GdtSeg
mul bx
mov word ptr V_GDTR.BASE,ax
mov word ptr V_GDTR.BASE+2,dx
ret
INIT_GDT endp
;----------------
INIT_LDT proc near
Inittg_ldt:
mov ax,fs:[si].BASEL
MOV BX,16
MUL BX
mov fs:[si].BASEL,ax
mov fs:[si].BASEM,dl
mov fs:[si].BASEH,dh
add si,size desc
loop Inittg_ldt
ret
INIT_LDT endp
;-------------------
INIT_IDT proc
mov bx,16
mov ax,IdtSeg
mul bx
mov word ptr V_IDTR.BASE,AX
mov word ptr V_IDTR.BASE+2,DX
RET
INIT_IDT ENDP
;----------------
EA20 proc ; 打开A20。
push ax
in al,92h
or al,2
out 92h,al
pop ax
ret
EA20 endp
DA20 proc ; 关闭A20。
push ax
in al,92h
and al,0fdh
out 92h,al
pop ax
ret
DA20 endp
RCodeSeg ends
end Start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -