+ -
当前位置:首页 → 问答吧 → 怎样用jmp指令从保护模式转换为实模式?

怎样用jmp指令从保护模式转换为实模式?

时间:2011-10-23

来源:互联网

从实模式通过jmp转为保护模式之后,再从保护模式通过jmp转为实模式,如果实模式与保护模式是两个独立的段,结果失败了,是一个段的话,能成功,为什么?
jump <selector>,<offsetv>:db 0eah;dw offsetv;dw selector

rseg segment use16
  start:
  ;初始化gdt及vgdt,加载gdtr
  lgdt fword vgdt
  mov eax,cr0
  or eax,1
  mov cr0,eax
  jump <pcode_sel>,<offset pbegin>---转入保护模式
  real:
  ;show shome thing
  jmp $
rseg ends

pseg segment use16
  pbegin:
  ;show something
  mov eax,cr0
  and eax,0fffffffeh
  mov cr0,eax
  jump <seg rseg>,<offset real>-----转回实模式失败?为什么?
pseg ends

gdtseg segment use16
  gdt label byte
  dummy descriptor<>
  PCODE descriptor<>
  pcode_sel = PCODE - gdt
  gdtlen = $ - gdt
  vgdtr pdesc<gdtlen-1,>
gdtseg ends
  end start


如果将实模式代码段及保护模式代码段合并为一个段,则能成功:gdt定义:
  CODE descriptor<>;指向rseg
  code_sel = CODE - gdt
rseg segment use16
  start:
  ;初始化gdt及vgdt,加载gdtr
  lgdt fword vgdt
  mov eax,cr0
  or eax,1
  mov cr0,eax
  jump <code_sel>,<offset virtual>---转入保护模式
 virtual:
  ;show something
  mov eax,cr0
  and eax,0fffffffeh
  mov cr0,eax
  jump <seg rseg>,<offset real>
  real:
  ;show shome thing
  jmp $
rseg ends

作者: liaozhicai   发布时间: 2011-10-23

如下代码,编译为启动代码,加载到7c00h处运行,显示为:s p,即在最初的实模式的显示s及切换到保护模式下显示p代码都能正常运行,但再切回到实模式后显示x代码段却没有执行,说明切换不成功,系统也没有崩溃,但没找到原因。请赐教,谢谢。

;功能:演示实方式和保护方式切换
;16位偏移的段间直接转移指令的宏定义
JUMP macro selector,offsetv
db 0eah ;操作码
dw offsetv ;16位偏移
dw selector ;段值或者选择子
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
;_______________________________________________________
STARTSEG = 7c0h
STARTUPSEG_addr = STARTSEG
pseg_addr = STARTUPSEG_addr + (STARTUPSEG_END - STARTUPSEG_BEGIN + 0fh)/10h
cseg_addr = pseg_addr + (pseg_end - pseg_begin + 0fh)/10h
gdtseg_addr = cseg_addr + (cseg_end - cseg_begin + 0fh)/10h
;__________________________________________________________
;起始代码段
STARTUPSEG segment para use16 'STARTUP'
assume cs:STARTUPSEG
STARTUPSEG_BEGIN:
  STARTUP:
  JUMP <cseg_addr>,<offset start>
STARTUPSEG_END:
STARTUPSEG ends
;_______________________________________________________
;保护代码段
pseg segment use16
pseg_begin:
  pbegin:
mov ax,DATAPRT_SEL
mov ds,ax
mov si,10h
mov [si],'p'    ;能正常显示
mov [si+1],0ch
;切换回实方式
mov eax,cr0
and eax,0fffffffeh
mov cr0,eax
;清指令预取队列,进入实方式
JUMP <cseg_addr>,<offset REAL>  
  pseg_len = $ - pbegin
pseg_end:
pseg ends
;_______________________________________________________
;代码段
cseg segment use16 ;16位段
assume cs:cseg, ds:gdtseg
cseg_begin:
  start:
mov ax,gdtseg_addr
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,pseg_addr
mul bx
mov PCODE.BASEL,ax
mov PCODE.BASEM,dl
mov PCODE.BASEH,dh
;设置代码段描述符
mov ax,cseg_addr
mul bx
mov CODE.BASEL,ax ;代码段开始偏移为0
mov CODE.BASEM,dl ;代码段界限已在定义时设置妥当
mov CODE.BASEH,dh
;show r
mov ax,0b800h
mov es,ax
mov di,0
mov es:[di],'s'          ;能正常显示
mov es:[di+1],0ch
;加载GDTR
LGDT fword ptr VGDTR
;
cli ;关中断
;切换到保护方式
mov eax,cr0
or eax,1
mov cr0,eax
;清指令预取队列,并真正进入保护方式
JUMP <PCODE_SEL>,<offset pbegin>
;
  VIRTUAL:;现在开始在保护方式下
mov ax,DATAPRT_SEL
mov ds,ax
mov si,10h
mov [si],'p'       ;程序运行,没有显示p字符!!!!!?
mov [si+1],0ch
;切换回实方式
mov eax,cr0
and eax,0fffffffeh
mov cr0,eax
;清指令预取队列,进入实方式
JUMP <cseg_addr>,<offset REAL>
;
  REAL: ;现在又回到实方式
;sti ;开中断
;
mov ax,0b800h
mov es,ax
mov di,160
mov es:[di],'r'
mov es:[di+1],07h
;
jmp $
  ;
cseg_end:
cseg ends
;____________________________________________________________
;GDT段
gdtseg segment use16 ;16位段
gdtseg_begin:
  GDT label byte ;全局描述表GDT
  ;________________________________
  DUMMY DESCRIPTOR <> ;空描述符
  ;________________________________
  PCODE DESCRIPTOR<pseg_len-1,,,ATCE,>
  PCODE_SEL = PCODE - GDT
  ;_______________________________
  CODE DESCRIPTOR <0ffffh,,,ATCE,>
  CODE_SEL = CODE - GDT ;代码段描述符的选择子
  ;_________________________________
  DATAPRT DESCRIPTOR <0ffffh,8000h,0bh,ATDW,0> 
  DATAPRT_SEL = DATAPRT - GDT ;屏幕显示段描述符的选择子
  ;__________________________________
  GDTLEN = $ - GDT
  ;
  VGDTR PDESC<GDTLEN-1,> ;伪描述符
gdtseg_end:
gdtseg ends
;-----------------------------------------------------------
end STARTUP

作者: liaozhicai   发布时间: 2011-10-23