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

📄 386ldt.asm

📁 suanfa de shiyan xw dui gan xingqu de pengyou you bangzhu
💻 ASM
字号:
;**********************************************************************
;   保护模式下的编程示例 			陈家祺	1996.6
;       ---局部描述符的应用方法	
;   1 实模式进入保护模式及保护模式返回实模式方法
;   2 保护模式下的指令操作(直接写屏,满屏显示'A')
;   * 环境: 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;offsetf -> IP
	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

dos_data  segment 		; 数据段
char		db   'A'	; 要显示的字符
save_ss		dw ?		; SS保存区

;	*****	GDT 描述符表	*****
gdt_def		LABEL	BYTE
		desc < >		; 必须为空描述符
gdt_kcs		desc <0ffffh,    ?,  ?,9ah,0fh,00h>	;00000 - fffffH (1Mb)
gdt_kds		desc <00000h,    ?,  ?,92h,00h,00h> 	;00000 - 00000H (1b)
gdt_kss		desc <00000h,    ?,  ?,96h,00h,00h>;(sp=)00400 - 00000H (1K)
gdt_ldt1	desc <ldt1_end-ldt1_def, ?, ?,82h,00h, ? > ;LDT1表的描述符  
gdt_ldt2	desc <ldt2_end-ldt2_def, ?, ?,82h,00h, ? > ;LDT2表的描述符  
gdt_end		LABEL	BYTE
					; 设置GDTR用
gdtsize		dw gdt_end-gdt_def	; GDT描述符表的长度
gdtload		dw ?			; GDT描述符表的线性基地址15-0,
		dw ?			; GDT描述符表的线性基地址31-16
;	*****	LDT1 描述符表	*****
ldt1_def	LABEL	BYTE
ldt1_uds	desc <0ffffh,8000h,0bh,92h,00h,00h>	;00000 - 0ffffH (64Kb)
ldt1_end	LABEL	BYTE
;	*****	LDT2 描述符表	*****
ldt2_def	LABEL	BYTE
ldt2_uds	desc <0ffffh,0000h,00h,92h,0fh,00h>	;00000 - fffffH (1Mb)
ldt2_end	LABEL	BYTE
				; GDT的选择子
gdt_kcs_sel 	equ 08h		; CS选择子
gdt_kds_sel 	equ 10h		; DS选择子
gdt_kss_sel 	equ 18h		; SS选择子
gdt_ldt1_sel 	equ 20h		; LDT1表的选择子
gdt_ldt2_sel 	equ 28h		; LDT2表的选择子
ldt1_uds_sel 	equ 04h		; LDT1的用户DS选择子
ldt2_uds_sel 	equ 04h		; LDT2的用户DS选择子

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
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	; 设置SP, 定义堆栈

	call prot			; 调用保护模式操作子程

	sti
	mov	ah,0
	int	16h			; BIOS键盘中断调用,等待按键!
	mov ah,4ch
	int 21h				; 返回DOS!
main endp

.386p
prot 	proc near
;	*****	设置GDT描述符的基地址	*****
	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

;	*****	设置LDT1描述符的基地址	*****
	mov di,offset gdt_ldt1		; 设置DS描述符的基地址
	mov bx,offset ldt1_def		; 将实模式DOS的段地址
	call copy_ldt_desc		; 换算为线性基地址

;	*****	设置LDT1描述符的基地址	*****
	mov di,offset gdt_ldt2		; 设置DS描述符的基地址
	mov bx,offset ldt2_def		; 将实模式DOS的段地址
	call copy_ldt_desc		; 换算为线性基地址

	LGDT fword ptr gdtsize		; 装载GDT

	mov ax,gdt_kss_sel		; 初始化保护模式的ss
	mov ss,ax			; 在保护模式下初始化ss将出错!
					; 原因?
	mov eax,cr0			
	or  al,1			; 设置控制寄存器CR0的PE位
	mov cr0,eax			; 进入保护模式
	jumpfar	gdt_kcs_sel,prot_user	; 清除指令队列,
prot_user:				; CS=gdt_kcs_sel(保护模式码段)
	call vram_disp			; 调用保护模式下显示子程

	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
	mov ds,ax
	mov ss,save_ss			; 恢复堆栈段
	ret
prot  endp

vram_disp proc near			; 保护模式下直接写屏子程
	pushad
	mov ax,gdt_kds_sel		; 设置GDT的数据段
	mov ds,ax
	mov dl,char			; 取出要显示字符'A'
	mov ax,gdt_ldt1_sel		; 设置LDT1的选择子	
	LLDT ax               		; 装载LDT1 -> LDTR
	mov ax,ldt1_uds_sel		; 设置LDT1的数据段
	mov ds,ax
	mov ebx,000000h
	mov ah,17h			; 字符颜色属性,蓝底白字
	mov al,dl			; 显示字符'A'
	mov [ebx],ax

	mov ax,gdt_ldt2_sel		; 设置LDT2的选择子		
	LLDT ax               		; 装载LDT2 -> LDTR
	mov ax,ldt2_uds_sel		; 设置LDT1的数据段
	mov ds,ax
	mov ebx,0b8002h
	mov ah,1eh			; 字符颜色属性,蓝底黄字
	mov al,dl			; 显示字符'A'
	mov [ebx],ax
	popad
	ret
vram_disp endp	

copy_desc proc near			; 设置描述符的基地址
	mov cx,10h			; 将实模式DOS的段地址
	mul cx				; 换算为24位线性地址
	mov [di].base_15_0,ax		; 存入描述符中
	mov [di].base_23_16 ,dl
	ret
copy_desc endp
copy_ldt_desc proc near			; 设置LDT描述符的基地址
	mov ax,ds			; 将LDT表的基地址
	mov cx,10h			; 换算为32位线性地址
	mul cx
	add ax,bx
	adc dx,0			
	mov [di].base_15_0,ax		; 存入描述符中
	mov [di].base_23_16 ,dl
	mov [di].base_31_24 ,dh
	ret
copy_ldt_desc endp

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

⌨️ 快捷键说明

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