实模式向保护模式跳转

不知道能不能把这个问题说清楚,我是被这个东西搞得很头晕,虽然原理听上去还不算难,但是,想把它真的弄得很透彻真的很不容易,下面

,我就试着把自己的思路顺一下:
一:我们知道机器从加电到引导系统这过程,首先是工作在实模式下的,也就是按实地址方式寻址。寻址空间也只能达到1M,(因为只有20位地址线,所以只可以寻址到2的20次方)而到了386时代,地址线已经达到了32位,所以不用分段分页机制下的独立寻址空间已经达到了4GB,(这个数字不难得到吧^_^),现代操作系统,比方说WINDOWS都是工作在这种方式下的,而要想得到这么强的寻址能力,显然,我们的8086汇编课本上没有教你怎么做,物理地址=段值*16+偏移,的时代已经一去不回来了,所以才有了保护模式,至于为什么叫保护模式,可能会有很多的理由,但是我想只要把特权级说出来,大家就可以很想当然的理解为出于安全的分级管理。所以,我们要做的工作就是完成,这一跳转!
二:那么在保护模式下又是怎么寻址的呢,很明显,还是会用到几个段寄存器,在这里它们并不是直接的表示为段的地址,而是换了个名字叫做选择子,故名思意,它的意思是,通过段寄存器,就可以找到相应段的入口,和以前一样嘛,呵呵,但是在哪里选呢,于是又加了这样一个数据结构GDT(全局描述符表)每个描述符项都是一个特定的数据结构,里面记录了该段的基址,界限,访问权限等信息。那么这个GDT又是放在哪里的呢,还能放在哪,寄存器无疑是最理想的空间,快,准,稳嘛!还有寄存器啊?对,就是寄存器多,于是又来了一个专门用于放置GDT的寄存器,gdtr,那每一个段都会在这里登记下来它所处的位置,即添加关于它的描述符项,然后再定义一个选择子,(其实就是相对于GDT表最顶部的相对位移),这样就可以由这个选择子找到这个段的入口,从而达到跳转的目的。
三:所以我们可以这样做:
    1:定义GDT段,准备GDT表;
    2:定义个数据,代码及堆栈段;
    3:为相应的段定义段选择子;
    4:用lgdt指令加载gdtr;
    5:打开A20地址线(这是历史的原因,因为开机以后20位地址线是没有打开的,需要手动打开才可以用)
    6:置cr0的PE位(这是一个控制寄存器,此位置1则可以启用保护模式)
    7:跳转,进入保护模式;(怎么跳?jmp,很好用的)
四:但是在跳的过程中,可能会遇到很多问题,Privilege,还有16位地址和32位地址不能直接跳等问题也很难。
而且,我们不能只跳过去,还要想到怎么才能跳出来,也就是怎么样才能再从保护模式跳回到实模式。
下面,我一边默写代码,一边回忆这样一个过程,大家可以从下面的代码里很好的理解我上面的思想。

None.gif #include         " pm.inc "         ;常量,宏,以及一些说明
None.giforg    0100h
None.gif    jmp    LABEL_BEGIN
None.gif
None.gif[section    .gdt]                ;全局描述符表段
None.gif;
======================================================
None.gif;GDT
None.gifLABEL_GDT:            Descriptor    
0 ,     0 ,     0                             ;空描述符
None.gifLABEL_DESC_CODE32:    Descriptor    
0 ,    SegCode32Len  -   1 ,     DA_C  +  Da_32    ;代码段,32位
None.gif
None.gifLABEL_DESC_VIDEO:            Descriptor    0B8000h,     0FFFFh,    DA_DRW    ;存在的可读写的数据段
None.gif
None.gif;GDT 结束
None.gif
None.gifGdtLen        equ    $ 
-  LABEL_GDT            ;GDT长度
None.gifGdtPtr        dw    GdtLen 
-   1                 ;GDT界限
None.gif            dd    
0                         ;GDT基地址
None.gif
None.gif;GDT选择子
None.gifSelectorCode32        equ        LABEL_DESC_CODE32 
-  LABEL_GDT
None.gifSelectorVideo            equ        LABEL_DESC_VIDEO 
-  LABEL_GDT
None.gif
None.gif;END of  [section .gdt]
None.gif;
========================================================

None.gif [section    .s16]
None.gif[BITS    
16 ]
None.gifLABEL_BEGIN:
None.gif    mov    ax,    cs
None.gif    mov    ds,    ax
None.gif    mov    es,    ax
None.gif    mov    ss,    ax
None.gif    mov    sp,    0100h                        ;指向本程序的开始
None.gif
None.gif    ;初始化32位代码段描述符
None.gif    xor    eax,    eax
None.gif    mov    ax,    cs
None.gif    shl    eax,    
4
None.gif    add    eax,    LABEL_SEG_CODE32
None.gif    mov    word    [LABEL_DESC_CODE32 
+   2 ],    ax
None.gif    shr    eax,    
16
None.gif    mov    
byte         [LABEL_DESC_CODE32  +   4 ],    al
None.gif    mov    
byte         [LABEL_DESC_CODE32  +   7 ],    ah
None.gif
None.gif    ;为加载gdtr做准备
None.gif    xor    eax,    eax
None.gif    mov    ax,    ds
None.gif    shl    eax,    
4
None.gif    add    eax,    LABEL_GDT
None.gif    mov    dword    [GdtPtr 
+ 2 ],    eax
None.gif
None.gif    ;加载gdtr
None.gif    lgdt    [GdtPtr]
None.gif
None.gif    ;关中断
None.gif    cli
None.gif
None.gif    ;打开地址线A20
None.gif    
in     al,    92h
None.gif    or    al,    00000010b
None.gif    out    92h,    al
None.gif
None.gif    ;准备切换到保护模式
None.gif    mov    eax,    cr0
None.gif    or    eax,    
1
None.gif    mov    cr0,    eax
None.gif
None.gif    ;真正进入保护方式
None.gif    jmp    dword    SelectorCode32:
0
None.gif
None.gif    ;End of [section .s16]
None.gif;
==================================================

None.gif
None.gif[section .s32]
None.gif[BITS 
32 ]
None.gifLABEL_SEG_CODE32:
None.gif mov ax, SelectorVideo
None.gif mov gs, ax
None.gif
None.gif mov edi, (
80   * 10   + 0 * 2   ;屏幕第10行,第0列
None.gif mov ah, 02h
None.gif mov al, 'P'
None.gif mov [gs:edi], ax
None.gif
None.gif jmp $
None.gifSegCode32Len equ $ 
-  LABEL_SEG_CODE32
None.gif;End of [Section .S32]
None.gif;
===================================================
None.gif

下面是我们Intel Architecture中看到的有关于保护模式的文档,先来看这个图:
segmentationpage.jpg
这个图很清楚的说明了我刚才提到的GDT是如何工作的,这里并没有LDT,但是有LinearAdress,和PhysicalAddress,关于三种地址的转换问题,我会在下一讲里谈到,其实上面也就是我们在操作系统课里强调最多段页式存储。在这里,你会看得更清楚,因为你懂得了它的原理!甚至我们都用代码实现了!爽吧!
好了,时间不早了,我要睡了,可能今天对这个问题还没有吃透,明天继续,看来,我用自己的语言把这个东西说一遍真的印象加深了很多,而且,本来以为懂的东西,结果还是很糊涂,本来看不下去的大段英文,现在想用自己的语言表达,力求精确的时候,我又不得不仔细的读它,看来,这样学习,还真是个好方法,您不妨试试,或许我们还可以多多交流!晚安!

转载于:https://www.cnblogs.com/stonecrazyking/archive/2006/03/06/343586.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值