zoukankan      html  css  js  c++  java
  • 实地址模式与保护模式之间的切换

    9.1  实地址模式与保护模式之间的切换

     

    我们知道,IA-32计算机在加电或者Reset信号有效之后,首先进入实地址模式,执行BIOS程序,然后再进入保护模式,执行Windows环境下的程序。因此,IA-32 CPU在工作的时候,需要从实地址模式切换到保护模式。从实地址模式切换到保护模式,通常需要建立描述符表(descriptor table),设置控制寄存器CR0的PE位,如例9.1所示。

     

    例9.1  IA-32 CPU从实地址模式切换到保护模式,然后又切换回实地址模式。

    ;

    ;IA-32 CPU enters into protected mode from real address mode,

    ;a string is displayed on the screen, IA-32 CPU returns into real

    ;address mode from protected mode.

    ;

    .386p

    .model   small,c

    .stack   100h

    ;

    Descriptor      STRUCT

      limit         word     0

      basel         word     0

      basem         byte     0

      attrib        word     0

      baseh         byte     0

    Descriptor      ENDS

    ;

    Data            Segment  use16

    ;

    gdt0          Descriptor <>

    ;

    DataSel       equ      $-gdt0

    DataDes       Descriptor <0ffffh,,,92h,>

    ;

    CodeSel       equ      $-gdt0

    CodeDes       Descriptor <0ffffh,,,98h,>

    ;

    VideoSel      equ      $-gdt0

    VideoDes      Descriptor <0ffffh,8000h,0Bh,92h,>

    ;

    GdtLen        equ      $-gdt0

    ;

    GdtPtr        word     GdtLen

    dword    0

    ;

    Mess          byte     ‘IA-32 CPU is in Protected Mode.’,0

    ;

    JmpTable      dword    0

    ;

    Data            ends

    ;

    Code            Segment  use16

        assume cs:Code,ds:Data

    ;

    Start:          xor      eax,eax          ;Clear eax.

    ;

    mov      ax,Data          ;Initialize DS.

    mov      ds,ax            ;

    ;

    ;Prepare for entering into protected mode.

    ;

    shl      eax,4          ;create base address for data segment

    ;

    mov      dword ptr [GdtPtr+2],eax ;Base address for load GDTR

    ;

    mov      DataDes.basel,ax ;Fill base address for data segment

    shr      eax,16           ;into data segment descriptor.

    mov      DataDes.basem,al ;

    mov      DataDes.baseh,ah ;

    ;

    xor      eax,eax              ;Fill base address for code segment

    mov      ax,Code          ;into code segment descriptor.

    shl      eax,4            ;

    mov      CodeDes.basel,ax ;

    shr      eax,16           ;

    mov      CodeDes.basem,al ;

    mov      CodeDes.baseh,ah ;

    ;

    lgdt     fword ptr GdtPtr ;Load GDTR

    ;

    cli                      ;Disable interrupt.

    mov      eax,cr0            ;SetPE of CR0 into 1.

    or       eax,1

    mov      cr0,eax

    ;

    mov      dx,CodeSel     ;Use “jmp far ptr [esi]” to flush

    shl      edx,16         ;instruction prefetch queue.

    mov      dx,offset Code16

    mov      JmpTable,edx

    lea      esi,JmpTable

    jmp      far ptr [esi]

    ;

    ;Enter into protected mode.

    ;

    Code16:         mov      ax,DataSel   ;The string is displayed on the screen.

    mov      ds,ax

    mov      ax,VideoSel

    mov      es,ax

    mov      si,offset Mess

    mov      di,80*46+48

    mov      ah,47h

    Load:           mov      al,[si]

    inc      si

    cmp      al,0

    jz       ReadyToRmode

    mov      es:[di],ax

    add      di,2

    jmp      Load

    ;

    ;Prepare for returning to real address mode.

    ;

    ReadyToRmode:   mov      eax,cr0        ;Clear PE of CR0.

    and      eax,0fffffffeh

    mov      cr0,eax

    ;

    mov      dx,seg Rmode   ;Use “jmp far ptr [esi]” to flush

    shl      edx,16         ;instruction prefetch queue.

    mov      dx,offset Rmode

    mov      JmpTable,edx

    lea      esi,JmpTable

    jmp      far ptr [esi]

    ;

    ;Return to real address mode.

    ;

    Rmode:          sti                     ;Set IF.

    ;

    mov      ax,Data        ;Initialize DS and ES.

    mov      ds,ax

    mov      es,ax

    ;

    mov      ax,4c00h       ;Retire.

    int      21h

    ;

    Code            ends                    ;Code segment is over.

    ;

                    end      Start          ;The source program is over.

    课堂练习:对于例9.1中所示的程序,我们可以在MASM 6.11环境下进行汇编和链接,然后运行并观察其结果:

    A.  启动PWB。

    B.  更改设置:点Options,在弹出的选单上选中Build Options,在弹出的Build Options窗口中选中Use Release Options,点OK。

    C.  打开源程序文件sam9-1.asm,建立可执行程序sam9-1.exe。注意,请不要进入CodeView环境去运行sam9-1.exe。

    D.  重启计算机,根据计算机的不同,进行适当操作,使其进入MS-DOS方式。

    E.  在MS-DOS方式下,运行sam9-1.exe,即可看到在屏幕上显示出的字符串。

    现在对例9.1中所示程序的工作原理进行分析:

    1.  声明结构类型Descriptor

    保护模式下的段寄存器:其内容不再是段的基地址,而是称之为选择符(selector),其功能在于从全局段描述符表(Global Descriptor Table,GDT)或者局部段描述符表(Local Descriptor Table,LDT)中选出一个段描述符。选择符的字段结构如表9.1所示。

    表9.1  选择符的字段结构

    b15~b3

    b2

    b1~b0

    Index

    TI

    RPL

    选择符的位b1~b0称之为请求特权级(Requested Privilege Level,RPL)。RPL的数字必须小于当前特权级(Current privilege level,CPL)的数字,才可以访问某个段的数据。CPL是当前正在执行的任务所具有的特权级,也就是段寄存器CS和SS中b1~b0所具有的数字。另外,段描述符的访问权限字节(字节5)的b6~b5称之为段描述符特权级(Descriptor privilege level,DPL)。DPL、CPL、RPL是Windows操作系统中保护机制的重要基础。

    TI位:为0时,说明段描述符在GDT中,应该访问GDT;为1时,说明段描述符在LDT中,应该访问LDT。

    Index:利用它可以从GDT或者LDT中选出一个段描述符。具体作法是,由CPU硬件首先把Index的值乘以8,然后把乘积加到段描述符表的基地址上。段描述符表的基地址和限长分别存在全局段描述符表寄存器(Global Descriptor Table Register,GDTR)和局部段描述符表寄存器(Local Descriptor Table Register,LDTR)中。

    GDT和LDT都放在内存中,由Windows操作系统维护。通常,系统任务的段描述符存放在GDT中,用户任务的段描述符存放在LDT中。每个段描述符表包含8192( )个段描述符。

    GDT和LDT中的段描述符可以认为是一种数据结构,每个段描述符具有8个字节的长度,其结构如表9.2所示。

    表9.2  段描述符的结构

    字节7

    字节6

    字节5

    字节4~2

    字节1~0

    基址b31~b24

    控制位

    段限b19~b16

    访问权限

    基址b23~b0

    段限b15~b0

               

    在例9.1中,所声明的结构类型Descriptor与表9.2所示的段描述符结构是完全一致的。

    2.  关于完全段

    本例中的数据段和代码段都使用了完全段来定义。原因在于只有使用完全段才可以实现在保护模式下,定义16位段的功能。

    3.  数据段

    定义结构变量必须在数据段中,而声明结构类型则可不必在数据段中。

    gdt0:NULL段描述符,Windows操作系统要求第一个段描述符必须定义为NULL。

    DataSel:定义数据段选择符。

    DataDes:定义数据段描述符,基地址需用指令填充。

    CodeSel:定义代码段选择符。

    CodeDes:定义代码段描述符,基地址需用指令填充。

    VideoSel:定义视频缓冲区段选择符。

    VideoDes:定义视频缓冲区段描述符。

    GdtLen:全局段描述符表限长。

    GdtPtr:指向全局段描述符表限长和基地址的指针。

    Mess:进入保护模式后显示在屏幕上的字符串。

    JmpTable:在jump指令的间接寻址方式下,用来存放转移目标地址。

    4.  代码段:初始化DS,建立数据段基地址,建立用来装入GDTR的基地址,把数据段基地址填入数据段描述符,把代码段基地址填入代码段描述符。

    5.  代码段:装全局描述符表寄存器指令

    该指令助记符用“LGDT”表示,其功能是把内存数据段中的GDT的限长和基地址装入GDTR。

    GDTR的字段结构如表9.3所示。

    表9.3  GDTR的字段结构

    b47~b16

    b15~b0

    GDT的基地址

    GDT的限长

    LGDT指令只需要一个操作数。由表9.3知道GDTR的长度具有6个字节,所以其操作数的类型也应该是6个字节。LGDT指令的形式和操作列在表9.4中。

    表9.4  LGDT指令的形式和操作

    汇编语句格式

    编码示例

    寻址方式与操作

    LGDT m16&32

    LGDT     fword ptr GdtPtr

    直接寻址

    注:在表9.4中,m代表memory,ptr代表pointer,以下同。

    LGDT指令只能由操作系统使用,用户程序不能使用。通常,LGDT指令运行在实地址模式下,以便于CPU在切换到保护模式以前能够执行初始化操作。

    6.  代码段:关中断,设置CR0的PE位,清除指令预取队列

    用cli指令关中断。

    控制寄存器(Control Register,CR)CR0具有32位的长度,其b0为保护模式允许位(Protection Enable,PE)。当该位为1时,允许CPU工作在保护模式下;当该位为0时,禁止CPU工作在保护模式下。系统加电启动时,该位被置0。

    用“jmp far ptr [esi]”指令,执行一个无条件转移,以便于清除指令预取队列,保证顺利地进入保护模式。此处jmp指令使用了间接寻址方式,方法是:首先把转移目标地址存入内存数据段变量JmpTable中,然后把JmpTable的偏移量传送到esi中,最后执行一个以esi内容为指针的far转移。

    7.  代码段:进入保护模式

    在屏幕上显示字符串“IA-32 CPU is i.n Protected Mode.”。此处采用直接写显示缓冲区的方法。

    显示缓冲区的基地址:实地址模式下为B8000H(以物理地址形式表示),保护模式下为000B8000H(以物理地址形式表示)。

    指定屏幕上的显示坐标:mov      di,80*46+48。屏幕上可显示字符的容量为24行×80字符。在显示缓冲区中,每个字符用两个字节来表示,高字节表示颜色与属性,低字节存储字符的ASCII代码。

    指定屏幕上的显示属性:mov      ah,47h,请参考MASM 6.11的联机帮助。

    8.  代码段:准备返回到实地址模式

    清除CR0的PE位,以便于CPU能够工作在实地址模式下。

    用“jmp far ptr [esi]”指令,执行一个无条件转移,以便于清除指令预取队列,保证顺利地返回到实地址模式。

    9.  代码段:返回到实地址模式

    设置ds和es,返回到系统。

    课堂练习:调节屏幕显示坐标和颜色与属性。

  • 相关阅读:
    ZOJ 3795 Grouping
    ZOJ 3791 An Easy Game
    ZOJ 3790 Consecutive Blocks
    POJ 1451 T9
    POJ 1141 Brackets Sequence
    POJ 2411 Mondriaan's Dream
    POJ 2513 Colored Sticks
    Eclipse 快捷键大全
    C# lock关键字(多线程)
    C# 内部类
  • 原文地址:https://www.cnblogs.com/wanghj-dz/p/3975107.html
Copyright © 2011-2022 走看看