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

📄 386p2b1.asm

📁 汇编学习经典,DOS环境可在 win2000下使用
💻 ASM
字号:
;**********************************************************************
;   保护模式下的编程示例 			陈家祺	1996.6
;
;   1 实模式进入保护模式及保护模式返回实模式方法
;   2 保护模式下的指令操作(直接写屏)
;   * 环境: 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

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

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

;	*****	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

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	; 定义堆栈
	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

	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

	LGDT fword ptr dtsize		; 装载GDT

	mov eax,cr0			
	or  al,1			; 设置控制寄存器CR0的PE位
	mov cr0,eax			; 进入保护模式
; ***** 进入保护模式 ******
	db 0eah				; 清除指令队列,
	dw offset prot_user		; CS=gdt_kcs_sel(保护模式码段)
	dw gdt_kcs_sel		
prot_user:
	call vram_disp			; 调用保护模式下显示子程

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

vram_disp proc near			;保护模式下显示子程
	pushad
	mov ax,gdt_uds_sel
	mov ds,ax
	mov cx,80*25			;直接写屏.
	mov ebx,0b8000h
	mov ah,17h			;字符颜色属性,蓝底白字
	mov al,'A'			;显示字符'A'
l1:	mov [ebx],ax
	add ebx,2
	loop l1
	popad
	ret
vram_disp endp	

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

dos_code ends
   	end start

⌨️ 快捷键说明

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