+ -
当前位置:首页 → 问答吧 → 在纯DOS下如何进入保护模式?

在纯DOS下如何进入保护模式?

时间:2010-11-06

来源:互联网

我把杨季文的《80X86汇编语言程序设计教程》中的T10-1.asm源代码
中的切换回实模式中的代码都删除,只留切换到保护模式的代码,我
是在纯DOS下运行的,可是一运行就会变成重新启动了,请问:这是怎
么回事?怎么做才能从纯DOS下进入保护模式?
附代码:
;程序名:T10-1.asm
;功能:演示实方式和保护方式切换

;16位偏移的段间直接转换指令的宏定义
jump macro selector,offsetv
  db 0eah ;操作码
dw offsetv ;16位偏移
dw selector ;段值或选择子
endm

;字符显示宏指令的定义
echoch macro ascii
  mov ah,2
mov dl,ascii
int 21h
endm

;存储段描述符结构类型的定义
descriptor struc
limitl dw 0 ;段界限(0--15)
basel dw 0 ;段基地址(0--15)
basem db 0 ;段基地址(16--23)
attributes dw 0 ;段属性
baseh db 0 ;段基地址(24--31)
descriptor ends

;伪描述符结构类型的定义
pdesc struc
limit dw 0 ;16界限
base dd 0 ;基地址
pdesc ends

;常量定义
atdw = 92h ;存在的可读写数据段属性值
atce = 98h ;存在的只执行代码段属性值

;
  .386P
;--------------------------------------------------------

;数据段
dseg segment use16 ;16位段
gdt label byte ;全局描述符表gdt
dummy descriptor <> ;空描述符
code descriptor <0ffffh,,,atce,>
code_sel =code-gdt ;代码段描述符的选择子
datas descriptor <0ffffh,0h,11h,atdw,0>
datas_sel =datas-gdt ;源数据段描述符的选择子
datad descriptor <0ffffh,,,atdw,>
datad_sel =datad-gdt ;目的数据段描述符的选择子
gdtlen =$-gdt
;
vgdtr pdesc <gdtlen-1,> ;伪描述符
;
bufferlen = 256 ;缓冲区字节长度
buffer db bufferlen dup(0) ;缓冲区
dseg ends

;-------------------------------------------------------------
;代码段
cseg segment use16 ; 16位段
  assume cs:cseg, ds:dseg
start:
  mov ax,dseg
mov ds,ax
;准备要加载到gdtr的伪描述符
mov bx,16
mul bx ;计算并设置gdt基地址
add ax,offset gdt ;界限已在定义时设置妥当
adc dx,0
mov word ptr vgdtr.base,ax
mov word ptr vgdtr.base+2,dx
;设置代码段描述符
mov ax,cs
mul bx
mov code.basel,ax ;代码段开始偏移为0
mov code.basem,dl ;代码段界限已在定义时设置妥当
mov code.baseh,dh
;设置目标数据段描述符
mov ax,ds
mul bx ;计算并设置目标数据段基地址
add ax,offset buffer
adc dx,0
mov datad.basel,ax
mov datad.basem,dl
mov datad.baseh,dh
;加载gdtr
lgdt fword ptr vgdtr
;
cli ;关中断
call ea20 ;打开地址线A20
;切换到保护模式
mov eax,cr0
or eax,1
mov cr0,eax
;清指令预取队列,并真正进入保护模式
jump <code_sel>,<offset virtual>
;
virtual: ;现在开始在保护方式下
  mov ax,datas_sel
mov ds,ax ;加载源数据段描述符
mov ax,datad_sel
mov es,ax ;加载目标数据段描述符 
cld
xor si,si ;设置指针初值
xor di,di
mov cx,bufferlen/4 ;设置4字节为单位的缓冲区长度
repz movsd ;传送

;切换回实模式
  ;这里我删除了大多数代码 

mov ax,4c00h ;结束
int 21h
;
toascii proc
  and al,0fh
  add al,'0'
  cmp al,'9'
  seta dl
  movzx dx,dl
  imul dx,7
  add al,dl
  ret  
toascii endp
;
;打开地址线A20
ea20 proc
  push ax
in al,92h
or al,2
out 92h,al
pop ax
ret
ea20 endp
;
;关闭地址线A20
da20 proc
  push ax
in al,92h
and al,0fdh ;0fdh=not 20h
out 92h,al
pop ax
ret
da20 endp
;
cseg ends
  end start

作者: leetow2003   发布时间: 2010-11-06

mov ax,4c00h
int 21h
在保护模式下,你是不能调用实模式下的中断的,所以你的那句结束退出是错误的,原来的例子是切换回实模式下才调用中断,由于你没有并没有建立IDT表,那么你的中断就引起计算机重启了

作者: lizi5803   发布时间: 2010-11-06