保护模式下的编程<二>

类别:编程语言 点击:0 评论:0 推荐:

控制寄存器:

       控制寄存器有CR0 CR1 CR2 CR3,其中CR1是保留的,在这里我重点介绍CR0,应为他跟分段和分页都有重要的联系,CR2和CR3不做介绍.

    控制寄存器的CR0的第一位用PE表示,他是用来控制分段的,当PE=0,处理器运行在实方式下,当PE=1,处理器运行在保护模式.在我门下面的代码中我将会设置CR0的PE位,进入保护模式.CR0的31位,是用来控制分页的.用PG表示.当PG=0时候禁用分页机制,当PG=1时候启用分页机制.  

下面我门来看看几个例子.

实模式和保护模式的切换

在实模式下输出一个B,在保护模式下输出一个A

ea20       macro

                push    ax

                in      al,92h

                or      al,00000010b

                out     92h,al

                pop     ax

                endm

;----------------------------------------------------------------------------

;关闭A20地址线

;----------------------------------------------------------------------------

da20      macro

                push    ax

                in      al,92h

                and     al,11111101b

                out     92h,al

pop     ax              

       endm               ;A20详见 http://www.xemean.net/data/article.asp?id=8

jump       macro     selector,offsetv

       db    0EAh

       dw   offsetv

       dw   selector

       endm              

 ;--------------------

descriptor       struc                          ;描述符的结构

limitl       dw   0

basel       dw   0

basem     db    0

attributes dw   0

baseh      db    0

descriptor       ends

;--------------------

pdesc      struc

limit dw   0

base dd    0

pdesc      ends

;

atdw=92h                                                 ; 存在可读写数据段类型

atce=98h                                                  ; 存在只执行代码段类型

atcer=9ah                                                        ; 存在可执行可读写的代码段类型

                                                        .386P

dseg    segment   use16 

;----------------------------------------

gdt   label byte                                                         ;全局描述符表

dummy   descriptor       <>

code    descriptor      <0FFFFh,,,atce,>                    ;代码段描述符     

code_sel=code-gdt                                                  ;选择子  

data    descriptor      <0FFFFh,,,atdw,>              ;数据段描述符

data_sel=data-gdt                                                    ;对应的选择子     

;注意:代码段又代码段的属性,数据段又数据段的属性.不要混淆否则无法正常运行

vcode   descriptor      <0FFFFh,,,atce,>              ;显示字符A的代码段描述符

vcode_sel=vcode-gdt                                               ;对应选择子

vbuf   descriptor      <0FFFFh,8000h,0bh,atdw,>

vbuf_sel=vbuf-gdt

normal  descriptor      <0FFFFh,,,atdw,>             ;描述符

normal_sel=normal-gdt                                            ;选择子

;-----------------------------------------

gdtlen=$-gdt

;

vgdtr       pdesc             <gdtlen-1,>    

dseg ends

;----------------------------------------

;代码段

vcseg   segment use16    'vcode'

        assume  cs:vcseg

vstart: mov     ax,0B800h                                                   ;直接写屏,输出A

        mov     ds,ax                   

        mov     bx,0

        mov     al,'A'

        mov     ah,07h

        mov     [bx],ax

        jump    <code_sel>,<offset toreal>

vcseg   ends

        end     vstart

 

cseg    segment use16    'code'                                         ;实模式

       assume    cs:cseg,ds:dseg                   

start:  

    mov     ax,dseg

       mov ds,ax

       mov bx,16                                                       ;*16转化成32位

       mul  bx

       add  ax,offset  gdt

       adc  dx,0

       mov word       ptr   vgdtr.base,ax

    mov     word    ptr     vgdtr.base+2,dx

       ;

       mov ax,cseg

       mul  bx

        mov     word    ptr     code.basel,ax

        mov     byte    ptr     code.basem,dl

        mov     byte    ptr     code.baseh,dh

       ;

       mov ax,dseg

       mul  bx

        mov     word    ptr     data.basel,ax

        mov     byte    ptr     data.basem,dl

        mov     byte    ptr     data.baseh,dh

       ;

        mov     ax,vcseg

        mul     bx

        mov     word    ptr     vcode.basel,ax

        mov     byte    ptr     vcode.basem,dl

        mov     byte    ptr     vcode.baseh,dh

       ;

              lgdt  qword     ptr   vgdtr              ;将伪描述符导入到GDTR,很重要的一步 

       cli

    ea20                             ;打开A20是能够寻址4G的空间.

       mov eax,cr0                                                     ;设置CR0,进入保护模式

       or    eax,1                                                        ;将CR0设置为1进入保护模式

       mov cr0,eax

    jump    <vcode_sel>,<offset vstart>     ;跳转到显示字符A的代码段

toreal:

    mov     ax,normal_sel

       mov ds,ax

       mov eax,cr0                                                     ;设置CR0,进入保护实模式 

       and  eax,0FFFFFFFEH                                     ;将CR0设置为0,返回到实模式

       mov cr0,eax

jump    <seg real>,<offset real>

real: 

       da20

    sti

    mov  ax,dseg                                           ;显示字符B

    mov ds,ax

    mov  dl,'B'

    mov  ah,2

    int  21h

    mov  ah,4Ch

    int    21h

cseg ends

       end  start

上面就是一个很简单的实模式和保护模式相互转换的例子,不过我也发了很长时间才明白的.这些都是我的一些心得,如有不正确的希望大家斧正.最后感谢CSDN汇编板块的csdsjkk() 指点.

 

 

 

 

参考资料:杨季文主编的<<80X86汇编语言程序设计教材>>

 

 

 

本文地址:http://com.8s8s.com/it/it28905.htm