⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 386spis5.asm

📁 汇编学习经典,DOS环境可在 win2000下使用
💻 ASM
字号:
;**********************************************************************
;   保护模式下的编程示例 --- 中断			陈家祺	1996.6
;
;   1 实模式进入保护模式及保护模式返回实模式方法
;   2 保护模式下的指令操作(清屏)
;   3 保护模式下的软中断调用方法
;   4 保护模式下的硬中断处理方法(时钟,键盘)
;   5 保护模式下的异常中断(13)处理方法
;   * 环境: MASM6.0, DOS6.2, 80486主机, Himem.sys, 不能装载Emm386.exe
;**********************************************************************
desc 	struc			;选择器描述符结构
  limit_15_0    dw ?		;界限15-0
  base_15_0   	dw ?		;基地址15-0
  base_23_16   	db ?		;基地址23-16
  access   	db ?		;访问权
  gran     	db ?		;粒度,类型,界限19-16
  base_31_24   	db ?		;基地址31-24
desc 	ends

idesc 	struc			;中断门描述符结构
  off_15_0    	dw ?		;入口偏移量15-0
  sel     	dw ?		;目标选择器
  no   		db 0		;
  access   	db ?		;访问权
  off_31_16    	dw ?		;入口偏移量31-16
idesc 	ends

dos_data  segment word public 'data'		;数据段
save_gdt	dw 4 dup (?)	;GDT保存区
save_idt	dw 4 dup (?)	;IDT保存区
save_ss		dw ?		;SS保存区
save_sp		dw ?		;SP保存区

dtsize		dw ?		;设置GDTR用
dtload		dw ?
		dw ?

idtsize		dw ?		;设置IDTR用
idtload		dw ?
		dw ?
tc		db 0		;时钟中断计数单元
;	*****	GDT 描述符表	*****
gdt_def		equ $
		desc < >	;空描述符
gdt_kcs		desc <0ffffh,0000h,00h,9ah,0fh,00h>	;00000 - fffffH (1Mb)
gdt_kds		desc <0ffffh,0000h,00h,92h,0fh,00h> 	;00000 - fffffH (1Mb)
gdt_kss		desc <00000h,0000h,00h,96h,00h,00h>
gdt_uds		desc <0ffffh,0000h,00h,92h,0fh,00h>	;00000 - fffffH (1Mb)
gdt_size	equ $-gdt_def

;	*****	IDT 描述符表	*****
idt_def		equ $
		idesc 8  dup (<4000h,0008h,00h,8eh,0000h >) 	;缺省中断门
idt_08		idesc <1000h,0008h,00h,8eh,0000h>		;时钟中断门
idt_09		idesc <1800h,0008h,00h,8eh,0000h>		;键盘中断门
		idesc 3  dup (<4000h,0008h,00h,8eh,0000h >) 	;缺省中断门
idt_13		idesc <3000h,0008h,00h,8fh,0000h>		;异常中断门
		idesc 18 dup (<4000h,0008h,00h,8eh,0000h >) 	;缺省中断门
idt_20h		idesc <2000h,0008h,00h,8fh,0000h>		;软中断门
		idesc 256-20h dup (<4000h,0008h,00h,8eh,0000h >);缺省中断门
idt_size	equ $-idt_def

dos_data	ends

dos_stack   	segment stack para 'stack'	;堆栈段
		db 1024 dup (0)
dos_stack_sp 	dw 0
dos_stack 	ends

dos_code 	segment word public 'code'	;代码段
	assume  cs:dos_code, ds:dos_data, ss:dos_stack

gdt_kcs_sel 	equ 08h		; CS选择器
gdt_kds_sel 	equ 10h		; DS选择器
gdt_kss_sel 	equ 18h		; SS选择器
gdt_uds_sel 	equ 20h		; 用户DS选择器

main 	proc near
start :
	mov ax,dos_data
	mov ds,ax			; 设置DS
	cli
	mov ax,dos_stack
	mov ss,ax			; 设置SS
	mov save_ss,ax			; 保存SS
	mov sp,offset dos_stack_sp	; 定义堆栈
	mov save_sp,sp			; 保存SP
	call prot			; 调用保护模式操作子程
	sti
	mov	ah,0
	int	16h			; BIOS键盘中断调用,等待按键!
	mov ah,4ch
	int 21h				; 返回DOS!
main endp

prot 	proc near
.386p
	SGDT fword ptr save_gdt		; 保存原GDT
	SIDT fword ptr save_idt		; 保存原IDT

	mov di,offset gdt_kcs		; 设置CS描述符的基地址
	mov ax,cs			; 将实模式DOS的段地址
	call copy_desc			; 换算为线性基地址

	mov di,offset gdt_kds		; 设置DS描述符的基地址
	mov ax,ds			; 将实模式DOS的段地址
	call copy_desc			; 换算为线性基地址

	mov di,offset gdt_kss		; 设置SS描述符的基地址
	mov ax,ss			; 将实模式DOS的段地址
	call copy_desc			; 换算为线性基地址

	mov ax,ds			; 计算GTD表的线性地址
	mov cx,10h
	mul cx
	add ax,offset gdt_def
	adc dx,0
	mov dtload,ax
	mov dtload+2,dx
	mov dtsize,gdt_size-1

	mov ax,ds			; 计算IDT表的线性地址
	mov cx,10h
	mul cx
	add ax,offset idt_def
	adc dx,0
	mov idtload,ax
	mov idtload+2,dx
	mov idtsize,idt_size-1

	LGDT fword ptr dtsize		; 装载GDT
	LIDT fword ptr idtsize		; 装载IDT

	mov eax,cr0			
	or  al,1			; 设置控制寄存器CR0的PE位
	mov cr0,eax			; 进入保护模式
; ***** 进入保护模式 ******
	db 0eah				; 清除指令队列,
	dw offset vram_disp		; CS=gdt_kcs_sel(保护模式码段)
	dw gdt_kcs_sel		
vram_disp:
	mov ax,gdt_uds_sel
	mov ds,ax
	mov cx,80*25			;清屏, 蓝色屏幕.
	mov ebx,0b8000h
	mov ah,10h			;字符颜色属性,背景色为蓝色
	mov al,' '
l1:	mov [ebx],ax
	add ebx,2
	loop l1

	sti
	mov dx,1000			;延时,等待外中断(时钟)产生
	mov ecx,0h
llc:	loop	llc
	dec dx	
	jnz  llc
	cli

	int 20h				;调用保护模式软中断
x:
	mov eax,cr0			
	and al,0feh			;清除控制寄存器CR0的PE位
	mov cr0,eax			;切换到实模式
	db 0eah				;清除指令队列,CS=dos_code(实模式码段)
	dw offset real_mode
	dw dos_code
; ***** 退出保护模式 *****
real_mode:
	mov ax,dos_data
	mov ds,ax

	LGDT fword ptr save_gdt		;恢复原GDT
	LIDT fword ptr save_idt		;恢复原IDT
	mov ss,save_ss			;恢复堆栈段
;	mov sp,save_sp
	ret
prot  endp

.8086
copy_desc proc near			;设置GDT描述符的基地址
	mov cx,10h			;将实模式DOS的段地址
	mul cx				;换算为线性地址
	mov [di].base_15_0,ax		;存入GDT描述符中
	mov [di].base_23_16 ,dl
	ret
copy_desc endp
.386p
	org	1000h			;保护模式时钟中断08h - 中断处理程序
int_08h	proc near			;每次中断tc=tc+20,
	pushad				;如果tc>127显示'*',否则显示' ';
	mov ax,gdt_kds_sel		;效果: '*'闪烁.
	mov ds,ax
	add tc,20
	cmp tc,127
	jb char0
	mov cl,'*'			;显示'*'
	jmp  char1
char0:	mov cl,' '			;显示' ',即清除'*'
char1:	mov ch,1eh			;字符颜色属性
	mov ax,gdt_uds_sel
	mov ds,ax
	mov ebx,0b8000h			;屏幕第0行
	mov [ebx],cx
	mov al,20h			;通知8259结束中断
	out 20h,al
	popad
	iretd
int_08h	endp

KEY_PA	equ 60h
KEY_PB	equ 61h
	org	1800h			;保护模式键盘中断09h - 中断处理程序
int_09h	proc near
	pushad
	in al,KEY_PA			;输入键盘扫描码
	mov al,10000000b		;复位键盘,发送应答
	out KEY_PB,al
	mov al,01000000b		;允许键盘工作
	out KEY_PB,al

	mov ebx,0b8000h+160*3		;屏幕第3行
	mov ah,1eh			;字符颜色属性
	mov al,'K'			;显示'K'
	mov [ebx],ax	
	mov al,20h			;通知8259结束中断
	out 20h,al
	popad
	iretd
int_09h	endp

	org	2000h			;保护模式软中断20h - 中断处理程序
int_20h	proc near
	pushad
	mov ebx,0b8000h			;屏幕第0行
	mov ah,1eh			;字符颜色属性
	mov al,'!'			;显示'!'
	mov [ebx],ax			
	popad
	iretd
int_20h	endp

	org	3000h			;保护模式异常中断13 - 中断处理程序
int_13 	proc near
	pushad
	mov ebx,0b8000h+160*4		;屏幕第4行
	mov ah,1eh			;字符颜色属性
	mov al,'?'			;显示'?'
	mov [ebx],ax	
	popad
;	jmp  x
	iretd
int_13 	endp

	org	4000h			;保护模式缺省中断 - 中断处理程序
int_nn 	proc near
	pushad
	mov ebx,0b8000h+160*5		;屏幕第5行
	mov ah,1eh			;字符颜色属性
	mov al,'#'			;显示'#'
	mov [ebx],ax	
	mov al,20h
	out 20h,al
	popad
	iretd
int_nn 	endp

dos_code ends
   	end start
;****************************** 源程序结束 ******************************

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -