📄 pmstart1.asm
字号:
;pmstart1.asm
;从实模式进入保护模式,8255并行输入并行输出,通过显存字符输出,K0=1返回实模式
include pmstart1.inc
.386p
;--------------------------
;全局描述符表GDT
GdtSeg segment para use16 'GDT'
gdt LABEL BYTE
Dummy Desc <> ;
NormalSel=$-gdt
Normal Desc <0ffffh,,,92h,,>
VideoSel=$-gdt
Video Desc <0ffffh,8000h,0bh,92h,,>
effgdt LABEL BYTE
TempCodeSel=$-gdt
TempCode Desc <0ffffh,TempCodeSeg,,98H,,>
SysCodeSel=$-gdt
Syscode Desc <SysCodeLen-1,SysCodeSeg,,98H,,>
SysDataSel=$-gdt
SysData Desc <0ffffh,SysDataSeg,,92H,,>
SysStack0Sel=$-gdt
SysStack Desc <SysStack0Len-1,SysStack0Seg,,92h,,>
; VideoSel=$-gdt ;放在这个位置字符无法输出
; Video Desc <0ffffh,8000H,0BH,92H,,>
GDTNUM=($-effgdt)/(size Desc)
GdtLen =$-gdt
GdtSeg ends
;----------------------------
;中断描述符表IDT
;IdtSeg segment
;IDT LABEL BYTE
;IdtSeg 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! '
hipm_len=$-hipm
endpm db ' Exit from the protected mode! '
endpm_len=$-endpm
SysDataSeg ends
;--------------------
SysCodeSeg segment para use16
assume cs:SysCodeSeg,ds:SysDataSeg
do_pm:
mov ax,SysStack0Sel ;;;;;;;;;;;;;;
mov ss,ax
mov sp,offset SysStack0Len ;;;;;;;;;;;;;;;
mov ax,SysDataSel
mov ds,ax
mov fs,ax
mov gs,ax
mov ax,VideoSel
mov es,ax
lea si,hipm ;输出字符,进入保护模式
mov cx,hipm_len
push ax
push cx
mov al,1 ;行
mov cl,160
mul cl
mov di,ax
pop cx
pop ax
call far ptr DispMess
xx: mov dx,0c40bh
mov al,89h
out dx,al
mov dx,0c40ah ;读8255C口
in al,dx
mov dx,0c408h
out dx,al
test al,01h
jz xx
lea si,endpm
mov cx,endpm_len
push ax
push cx
mov al,2 ;行
mov cl,160
mul cl
mov di,ax
pop cx
pop ax
call far ptr DispMess
JUMP16 TempCodeSel,<OFFSET ToReal>
DispMess proc ;字符串显示
push di
cld
dispa1:
lodsb
mov ah,34h
stosw
loop dispa1
pop di
ret
DispCopyLen=$-DispMess
DispMess endp
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
CALL INIT_GDT ; 初始化全局描述符表GDT
; CALL INIT_IDT ; 初始化中断描述符表IDT
POP DS
MOV SP_VALUE,SP
MOV SS_VALUE,SS
; SIDT QWORD PTR RealIdtr ;为了回到实方式后,恢复原IDTR之内容,先保存IDTR
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 + -