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

📄 386idt.asm

📁 suanfa de shiyan xw dui gan xingqu de pengyou you bangzhu
💻 ASM
字号:
;**********************************************************************
;   保护模式下的编程示例 --- 中断			陈家祺	1996.6
;
;   1 实模式进入保护模式及保护模式返回实模式方法
;   2 保护模式下的指令操作(清屏)
;   3 保护模式下的软中断调用方法
;   4 保护模式下的硬中断处理方法(时钟,键盘)
;   5 保护模式下的异常中断(13)处理方法
;   * 环境: MASM6.0,TASM3.0, DOS6.2, 80486主机, Himem.sys, 不能装载Emm386.exe
;           不能装载Emm386.exe,因为Emm386.exe装载后,cpu处于虚拟8086方式下
;**********************************************************************
jumpfar	MACRO	segf,offsetf		; 保护模式跳转指令
	db 0eah				; 功能与目的:
	dw offsetf			; 1. 清除指令队列
	dw segf				; 2. segf -> CS
	ENDM

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  		; 数据段
tc		db 0		; 时钟中断计数单元,用于显示更新
tn		dw 0		; 时钟中断计数单元,用于程序延时
save_idt	dw 4 dup (?)	; IDT保存区
save_ss		dw ?		; SS保存区

;	*****	GDT 描述符表	*****
gdt_def		LABEL	BYTE
		desc < >	; 空描述符
gdt_kcs		desc <0ffffh,  ?  , ? ,9ah,0fh,00h>	;00000 - fffffH (1Mb)
gdt_kds		desc <00002h,  ?  , ? ,92h,00h,00h> 	;00000 - 00002H (3 b)
gdt_kss		desc <00000h,  ?  , ? ,96h,00h,00h>
gdt_uds		desc <0ffffh,8000h,0bh,92h,00h,00h>	;00000 - 0ffffH (64k)
gdt_end		LABEL	BYTE

;	*****	IDT 描述符表	*****
idt_def		LABEL	BYTE
		idesc 8  dup (<int_nn,0008h,00h,8eh,0000h >) 	; 缺省中断门
idt_08		idesc <int_08h,0008h,00h,8eh,0000h>		; 时钟中断门
idt_09		idesc <int_09h,0008h,00h,8eh,0000h>		; 键盘中断门
		idesc 3  dup (<int_nn,0008h,00h,8eh,0000h >) 	; 缺省中断门
idt_13		idesc <int_13,0008h,00h,8fh,0000h>		; 异常13中断门
		idesc 18 dup (<int_nn,0008h,00h,8eh,0000h >) 	; 缺省中断门
idt_20h		idesc <int_20h,0008h,00h,8fh,0000h>		; 软中断门
		idesc 256-21h dup (<int_nn,0008h,00h,8eh,0000h >); 缺省中断门
idt_end		LABEL	BYTE
					; 设置GDTR用
gdtsize		dw gdt_end-gdt_def	; GDT描述符表的长度
gdtload		dw ?			; GDT表的首地址(线性地址)
		dw ?
					; 设置IDTR用
idtsize		dw idt_end-idt_def	; IDT描述符表的长度
idtload		dw ?			; IDT表的首地址(线性地址)
		dw ?
dos_data	ends

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

dos_code 	segment  		; 代码段
	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
	call prot			; 调用保护模式操作子程
	sti
	mov ah,0
	int 16h				; BIOS键盘中断调用,等待按键!
	mov ah,4ch
	int 21h				; 返回DOS!
main endp

.386p
prot 	proc near
	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 gdtload,ax
	mov gdtload+2,dx

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

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

	mov ax,gdt_kss_sel		; 设置保护模式的SS
	mov ss,ax

	mov eax,cr0			
	or  al,1			; 设置控制寄存器CR0的PE位
	mov cr0,eax			; 进入保护模式
	jumpfar	gdt_kcs_sel,wait_intr	; 清除指令队列,CS=gdt_kcs_sel(保护模式码段) 
wait_intr:
	sti
conti:	mov ax,gdt_kds_sel
	mov ds,ax
	cmp tn, 18*5			; 如果tn<18*5(5秒),循环等待中断
	jnz conti
	cli

	int 20h				; 调用保护模式软中断

	mov eax,cr0			
	and al,0feh			; 清除控制寄存器CR0的PE位
	mov cr0,eax			; 切换到实模式
	jumpfar	dos_code,real_mode	; 清除指令队列,CS=dos_code(实模式码段) 
real_mode:
	mov ax,dos_data			; 恢复DOS的DS
	mov ds,ax

	LIDT fword ptr save_idt		; 恢复原IDT
	mov ss,save_ss			; 恢复DOS的SS
	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
	; 保护模式时钟中断08h - 中断处理程序
int_08h	proc near			; 每次中断tc=tc+20,
	pushad				; 如果tc>127显示'*',否则显示' ';
	mov ax,gdt_kds_sel		; 效果: '*'闪烁.
	mov ds,ax
	inc tn				; tn增1
	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,000000h			; 屏幕第0行
	mov [ebx],cx
	mov al,20h			; 通知8259结束中断
	out 20h,al
	popad
	iretd
int_08h	endp

KEY_PA	equ 60h
KEY_PB	equ 61h
	; 保护模式键盘中断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 ax,gdt_uds_sel
	mov ds,ax
	mov bx,160*3			; 屏幕第3行
	mov ah,1eh			; 字符颜色属性
	mov al,'K'			; 显示'K'
	mov [bx],ax	
	mov al,20h			; 通知8259结束中断
	out 20h,al
	popad
	iretd
int_09h	endp

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

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

	; 保护模式缺省中断 - 中断处理程序
int_nn 	proc near
	pushad
	mov  ax,gdt_uds_sel
	mov  ds,ax
	mov  bx,160*5			; 屏幕第5行
	mov  ah,1eh			; 字符颜色属性
	mov  al,'#'			; 显示'#'
	mov  [bx],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 + -