Windows 版 (精华区)

作  家: xx01 (Bill) on board 'operatingsys'
题  目: 80386保护模式简介(1)
来  源: 哈尔滨紫丁香站
日  期: Tue May 20 13:15:43 1997
出  处: xixixi.bbs@bbs.xmu.edu.cn

标  题: 80386 保护模式简介 -1
发信站: 鼓浪听涛 (Sun May 18 16:22:09 1997)



                                                      ┌┐┌┐∞
      【 80386保护模式简介 】                    ┘└┘└┘

--------------------------------------------------------------------------
    在保护模式下有很多新的名词 ,包含 GDT.LDT.IDT 以及 CR0-CR3 ,笔者对保护
模式并不清楚 ,所以底下资料可能有错误。这里使用大量的线性记忆体观念 ,请您
一定要从头往後看 ,否则很可能会看不懂 ,且必须懂线性记忆体计算方式。

--------------------------------------------------------------------------
【 GDT 介绍 】
    在真实模式下每个区段都等於64K ,可是保护模式下每个区段的大小却是可变动
的 ,每个区段有多大呢 ,就是由 GDT 来决定。


    您可以用 SGDT CS:[BX] 的方式将 GDT 的值读出 ,它的长度为 6 BYTE ,底下
    是笔者写的小程式读出。

    XXXX:0000  FF 0F 00 20 C0 00
                     ^^^^^^^^^^^GDT表所在的线性记忆体位址
               ^^^^^GDT表长度+1

将此表资料读出来.
X:00C02000 00 00 00 00 00 00 00 00-FF FF 00 A0 C2 9B 40 00 ........... B.@.
X:00C02010 FF FF B0 DD 01 93 40 00-FF FF E0 B3 00 9A 00 00 ..0]..@...`3....
X:00C02020 FF FF E0 B3 00 93 00 00-00 00 00 20 C1 82 80 00 ..`3....... A...
X:00C02030 00 00 00 20 C1 93 C0 00-00 00 00 20 C0 93 C0 00 ... A.@.... @.@.
X:00C02040 00 00 00 00 00 92 40 00-FF FF 00 80 0B 92 40 00 ......@.......@.
                                .
                                .
                                .
                                .
它所代表的意思是如下图所示:(每组 8 byte)

        ┌——————————————————————┐
       1│                Limit bit 0-15              │ 0 byte
        ├——————————————————————┤
       3│                Base bit 0-15               │ 2
        ├——————————┬———————————┤
       5│       存取权       │    Base bit 16-23    │ 4
        ├——————————┼———————————┤
       7│   Base bit 24-31   │G│..│limit bit 16-19│ 6
        └——————————┴———————————┘
            "G"代表 Limit 的单位是 Byte 或 PAGE(4K)

所以....

#0000  Segment not present.
#0008  Base=00C2A000  Limit=0000FFFF  Flags=9B  USE32  Byte granularity
#0010  Base=0001DDB0  Limit=0000FFFF  Flags=93  USE32  Byte granularity
#0018  Base=0000B3E0  Limit=0000FFFF  Flags=9A  USE16  Byte granularity
#0020  Base=0000B3E0  Limit=0000FFFF  Flags=93  USE16  Byte granularity
#0028  Base=00C12000  Limit=00000000  Flags=82         Page granularity
#0030  Base=00C12000  Limit=00000000  Flags=93  USE32  Page granularity
#0038  Base=00C02000  Limit=00000000  Flags=93  USE32  Page granularity
#0040  Base=00000000  Limit=00000000  Flags=92  USE32  Byte granularity
#0048  Base=000B8000  Limit=0000FFFF  Flags=92  USE32  Byte granularity
#0050  Base=0001F56C  Limit=000007FF  Flags=92  USE32  Byte granularity
#0058  Base=00000000  Limit=00000144  Flags=92  USE32  Page granularity
#0060  Base=00000000  Limit=00000144  Flags=93  USE32  Page granularity
#0068  Base=00127F48  Limit=0000C32F  Flags=9B  USE16  Byte granularity
#0070  Base=00134278  Limit=000028F7  Flags=93  USE16  Byte granularity
#0078  Base=00000000  Limit=00000000  Flags=92  USE16  Byte granularity
^^^^^Selector                              ^^存取权

Base 就是指这个Secector:00000000对应到线性记忆体的何处 ,也就是说将线性记
忆体从 Base 所指的地方开始长度为 Limit ,剪下来变成一个独立的区段 ,如果您
在该区段想看超过 LIMIT 长度的记忆体 ,则会发生保护模式错误...应用程式可拦
截所发生的中断适当的加以处理。
注意 ,Limit的单位可以是 byte ,也可以是page(4k) ,由 "G" 是否为 1 来决定

至於 Selector 的数值我猜想应该是被标上 8 的倍数吧 ,因为很多书都是如此介
绍它。

--------------------------------------------------------------------------
【 LDT 介绍 】
    上面介绍了 GDT 可以设定很多个Secector ,而 LDT 则是在这些被定义出来
的Selector中再切割出更小的单元。也就是说 LDT 的资料长度只有 2 BYTE ,这
个值直接就是指 Selector。

※这个命令必需在最高权力下才能执行 ,所以笔者使用 386DEBUG 来执行 ,在传
  统 Real Mode/V86 都不能执行。

C:\>386debug 386debug.exp   (改过的.exp档)
000C:0002743C 660F0007                 SLDT     [EDI]
-T
-D EDI
0014:00000000  28 00                    <-- LDT 所指的Selector为0028
根据 GDT 的资料查表得到下表 ,但是由於 0028 这段落禁止观看 ,所以我改看0030
的段落 ,因为它的 Base 是一样的。

#0028  Base=00C12000  Limit=00000000  Flags=82         Page granularity
#0030  Base=00C12000  Limit=00000000  Flags=93  USE32  Page granularity

-D 30:0
0030:00000000  FF 00 F0 CE 09 92 40 00-31 00 00 00 CA 9B C0 00 ..pN..@.1...J.@.
0030:00000010  31 00 00 00 CA 93 C0 00-FF FF 00 80 0B 92 40 00 1...J.@.......@.
0030:00000020  FF 00 F0 CE 09 92 40 00-4D 00 90 CE 09 92 40 00 ..pN..@.M..N..@.
0030:00000030  44 01 00 00 00 93 C0 00-00 00 00 00 00 92 40 00 D.....@.......@.
0030:00000040  FF FF 00 80 0B 92 40 00-00 00 00 00 00 92 40 00 ......@.......@.
0030:00000050  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0030:00000060  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0030:00000070  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

-DL 0
#0004  Base=0009CEF0  Limit=000000FF  Flags=92  USE32  Byte granularity
#000C  Base=00CA0000  Limit=00000031  Flags=9B  USE32  Page granularity
#0014  Base=00CA0000  Limit=00000031  Flags=93  USE32  Page granularity
#001C  Base=000B8000  Limit=0000FFFF  Flags=92  USE32  Byte granularity
#0024  Base=0009CEF0  Limit=000000FF  Flags=92  USE32  Byte granularity
#002C  Base=0009CE90  Limit=0000004D  Flags=92  USE32  Byte granularity
#0034  Base=00000000  Limit=00000144  Flags=93  USE32  Page granularity
#003C  Base=00000000  Limit=00000000  Flags=92  USE32  Byte granularity
#0044  Base=000B8000  Limit=0000FFFF  Flags=92  USE32  Byte granularity
#004C  Base=00000000  Limit=00000000  Flags=92  USE32  Byte granularity
#0054  Segment not present.
#005C  Segment not present.
#0064  Segment not present.
#006C  Segment not present.
#0074  Segment not present.
#007C  Segment not present.

--------------------------------------------------------------------------
【 IDT 介绍 】
    在以往中断向量表都是用 4 byte 来表示 ,但是在保护模式下则由 8 byte 表
示 ,至於那几个 byte 表示什麽 ,笔者还未搞懂 ,底下只弄懂几个。


C:\>386debug 386debug.exp   (改过的.exp档)
000C:00027434 660F010F                 SIDT     [EDI]
-D EDI
0014:00000000  FF 07 6C F5 01 00 .. ..-.. .. .. .. .. .. .. ..
                     ^^^^^^^^^^^线性记忆体位址
               ^^^^^长+1
因为该线性记忆体已对映到 50:0
#0050  Base=0001F56C  Limit=000007FF  Flags=92  USE32  Byte granularity
所以:
0050:00000000  00 34 08 00 00 EE 00 00-0A 34 08 00 00 EE 00 00 .4...n...4...n..
0050:00000010  14 34 08 00 00 EE 00 00-1E 34 08 00 00 EE 00 00 .4...n...4...n..
0050:00000020  28 34 08 00 00 EE 00 00-32 34 08 00 00 EE 00 00 (4...n..24...n..
0050:00000030  3C 34 08 00 00 EE 00 00-6C 16 C8 0F 00 8E 00 00 <4...n..F4...n..
0050:00000040  50 34 08 00 00 EE 00 00-5A 34 08 00 00 EE 00 00 P4...n..Z4...n..
0050:00000050  64 34 08 00 00 EE 00 00-6E 34 08 00 00 EE 00 00 d4...n..n4...n..
0050:00000060  78 34 08 00 00 EE 00 00-82 34 08 00 00 EE 00 00 x4...n...4...n..
0050:00000070  8C 34 08 00 00 EE 00 00-96 34 08 00 00 EE 00 00 .4...n...4...n..

-DI 0
#0000  Selector=0008  Offset=00003400  Flags=EE         ;int_0
#0001  Selector=0008  Offset=0000340A  Flags=EE         ;int_1
#0002  Selector=0008  Offset=00003414  Flags=EE         ;int_2
#0003  Selector=0008  Offset=0000341E  Flags=EE         ;int_3
#0004  Selector=0008  Offset=00003428  Flags=EE
#0005  Selector=0008  Offset=00003432  Flags=EE
#0006  Selector=0008  Offset=0000343C  Flags=EE
#0007  Selector=0FC8  Offset=0000166C  Flags=8E         ;此处为Q387使用
#0008  Selector=0008  Offset=00003450  Flags=EE
#0009  Selector=0008  Offset=0000345A  Flags=EE
#000A  Selector=0008  Offset=00003464  Flags=EE
#000B  Selector=0008  Offset=0000346E  Flags=EE
#000C  Selector=0008  Offset=00003478  Flags=EE
#000D  Selector=0008  Offset=00003482  Flags=EE
#000E  Selector=0008  Offset=0000348C  Flags=EE
#000F  Selector=0008  Offset=00003496  Flags=EE

请仔细看一看这个表的对应情形 ,笔者故意载入Q387 以便让 INT_7 的 Selector 与
众不同 ,让您更易判断中断表对应关系。
--------------------------------------------------------------------------
实例解说:
底下是读取 SoftICE INT_0 的程式码□例:

Load IDT
LDT = FF 07 12 C0 80 00 所以观看 0080C012 的记忆体
  0080C012  47 2C 18 00 00 EE 00 00-4C 2C 18 00 00 EE 00 00  G,...□.L,...□.
  0080C022  51 2C 18 00 00 EE 00 00-56 2C 18 00 00 EE 00 00  Q,...□.V,...□.
  0080C032  5B 2C 18 00 00 EE 00 00-60 2C 18 00 00 EE 00 00  [,...□.`,...□.
  0080C042  65 2C 18 00 00 EE 00 00-6A 2C 18 00 00 EE 00 00  e,...□.j,...□.
  0080C052  6F 2C 18 00 00 EE 00 00-74 2C 18 00 00 EE 00 00  o,...□.t,...□.
  0080C062  79 2C 18 00 00 EE 00 00-7E 2C 18 00 00 EE 00 00  y,...□.~,...□.
由此得知 INT_0 是放在 0018:00002C47 的位址 ,於是查GDT表..


Load GDT
GDT = C8 00 18 C8 80 00 所以观看 0080C818 的记忆体
  0080C818  00 00 00 00 00 00 00 00-FF FF 10 11 83 93 00 00  ..............
  0080C828  FF FF 00 6E 81 93 00 00-FF FF 00 6E 81 9B 00 00  ...n.....n..
  0080C838  FF FF 00 00 00 93 CF 00-FF 7F 00 00 0B 92 00 00  .....□.....
  0080C848  FF 7F 00 80 0B 92 00 00-FF FF 00 00 0C 92 00 00  ...........
  0080C858  FF FF F0 32 82 9A 00 00-FF FF 00 C0 80 93 C0 00  ..□.....□□
  0080C868  0F 00 00 C0 7F 92 C0 00-68 20 00 00 81 8B 00 00  ...□□h ....
得到 Selector=0018=线性记忆体位址 816E00 处

於是我们就可以得知该中断程式放在 816E00:2C47 了 ,於是笔者把 816E00 的记忆体
搬到 8000:0000 ,然後用 DEBUG 来查看。

-u 8000:2c47
8000:2C47 6A00           PUSH   00
8000:2C49 E9F4D6         JMP    0340
8000:2C4C 6A01           PUSH   01
8000:2C4E E9C7D8         JMP    0518
8000:2C51 6A02           PUSH   02
8000:2C53 E98ADC         JMP    08E0
8000:2C56 6A03           PUSH   03
8000:2C58 E9D6DC         JMP    0931
8000:2C5B 6A04           PUSH   04
8000:2C5D E9E0D6         JMP    0340
8000:2C60 6A05           PUSH   05
8000:2C62 E9DBD6         JMP    0340
8000:2C65 6A06           PUSH   06
8000:2C67 E943DF         JMP    0BAD
8000:2C6A 6A07           PUSH   07
8000:2C6C E975E0         JMP    0CE4
8000:2C6F 6A08           PUSH   08
8000:2C71 E97BE1         JMP    0DEF
8000:2C74 6A09           PUSH   09
8000:2C76 E91605         JMP    318F
8000:2C79 6A0A           PUSH   0A
8000:2C7B E9C4D5         JMP    0242
8000:2C7E 6A0B           PUSH   0B
8000:2C80 E9BFD5         JMP    0242

--------------------------------------------------------------------------
看了上面几个例子後 ,再来就是练习进入保护模式 ,底下的例子请勿载入 EMM 系
列的保护模式软体 ,以免等级权限相冲当机。

code    segment
        assume  cs:code,ds:code
start   proc    near
        jmp     next

buffer1 db      18h,00h,00h,00h,00h,00h
;               ---+--- ------+--------
;                  |          |
;                  |          |
;                  |          GDT 表的记忆体位址
;                  |
;                  +----------GDT 表的长度
;
;
buffer2 db      000h,000h,000h,000h,000h,000h,000h,000h ;保留段
        db      0ffh,0ffh,000h,000h,000h,09bh,000h,000h ;程式段code:0
        db      0ffh,0ffh,000h,080h,00bh,093h,000h,000h ;萤幕段B800:0
        db      0100h dup (0)
;                         ------+-------
;                               |
;                               |
;                               线性记忆体位址
;
msg_1   db      'Enter Protect Mode !'
msg_2   db      0dh,0ah,'Return Real Mode !',0dh,0ah,'$'
386p
next :
        mov     ax,0600h        ;
        mov     bx,0700h        ;
        mov     cx,0000h        ;
        mov     dx,184fh        ;
        int     10h             ; CLS
        mov     ah,02h          ;
        mov     bh,00h          ;
        mov     dx,0100h        ;
        int     10h             ;
        mov     ax,cs
        mov     ds,ax
        mov     es,ax
        xor     eax,eax
        xor     ebx,ebx
        mov     ax,cs
        mov     cl,04h
        shl     eax,cl
        mov     bx,offset buffer2
        add     eax,ebx
        mov     bx,offset buffer1+2
        mov     cs:[bx],eax             ;GDT 位址设定
        NOP
        xor     eax,eax
        xor     ebx,ebx
        mov     ax,cs
        mov     cl,04h
        shl     eax,cl
        add     eax,ebx
        mov     bx,offset buffer2
        mov     cs:[bx+0ah],eax                 ;GDT Table 设定
        mov     byte ptr cs:[bx+0dh],9bh        ;存取权
        mov     ax,cs
        mov     ds,ax
        mov     es,ax
        mov     bx,offset buffer1
        xor     ecx,ecx
        cli
        cli
        lgdt    cs:[bx]                         ;载入GDT
        mov     eax,cr0
        or      eax,01h
        mov     cr0,eax
        jmp     protection                      ;进入保护模式
protection :
        db      66h
        mov     ax,code
        mov     ds,ax
        mov     si,offset msg_1
        mov     bx,0010h
        mov     es,bx
        mov     di,0000h
        mov     cx,0014h
        mov     ah,70h
show :
        cld                                     ;将CS:MSG_1搬到 0010:00000000
        lodsb                                   ;(0010的区段=B8000 请参考GDT
        stosw                                   ; 表)
        loop    show                            ;
        mov     eax,cr0
        and     al,not 1
        mov     cr0,eax
        db      0eah
        dw      real_mode,code                  ;返回真实模式
real_mode :
        sti
        mov     ax,cs
        mov     ds,ax
        mov     ah,09h
        mov     dx,offset msg_2
        int     21h
        mov     ax,4cffh
        int     21h
        mov     ax,4cffh
        int     21h
start   endp
code    ends
        end     start

--------------------------------------------------------------------------
    上面这个例子并没有设定 IDT (中断表) ,如果您要设定中断表的话 ,记得返回
真实模式时要还原 IDT 表.
--------------------------------------------------------------------------
    如果您希望在载入 QEMM386 後还能正常进入保护模式的话 ,则必需透过 VCPI
的命令来切入保护模式 ,详情可翻阅 VCPI 的书籍。



--
※ 来源:.鼓浪听涛 bbs.xmu.edu.cn.[FROM: SunLAB.xmu.edu.]

--
※ 来源:·哈尔滨紫丁香站 bbs1.hit.edu.cn·[FROM: xixixi.bbs@bbs.xmu.e] 
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:207.303毫秒