保护模式

核心目的:实现由实模式到保护模式的转换

核心步骤:

    1)程序定义了GDT数据结构

    2)16位代码进行了一些与GDT有关的操作

    3)程序最后跳到32位代码中做了一点操作显存的工作

进入保护模式的主要步骤:

    1)准备GDT

    2)用lgdt加载gdtr

    3)关中断、打开A20

    4)置cr0的PE位

    5)跳转,进入保护模式

逻辑地址到线性地址的转换:

    1)先从GDTR寄存器中获得GDT基址。

    2)然后再GDT中以段选择器高13位位置索引值得到段描述符。

    3)段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址yyyyyyyy才得到最后的线性地址。

怎样查看线性地址的内容:

    sudo ndisasm -o 0x7c00 pmtest1.bin >> wz.asm 同

    x /80bx 0x00007c80 命令对比,可以看到线性地址中的内容一一对应



; ==========================================

; pmtest1.asm

; 编译方法:nasm pmtest1.asm -o pmtest1.bin

; ==========================================

%include "pm.inc" ; 常量, 宏, 以及一些说明

org 07c00h

        jmp LABEL_BEGIN


[SECTION .gdt]

; GDT

;                                                           段基址,      段界限 ,                       属性

LABEL_GDT:   Descriptor                    0,                0,                                0          ; 空描述符

LABEL_DESC_CODE32: Descriptor   0,                 SegCode32Len - 1,    DA_C + DA_32; 非一致代码段

LABEL_DESC_VIDEO:  Descriptor      0B8000h,    0ffffh,                            DA_DRW     ; 显存首地址

; GDT 结束


GdtLen equ $ - LABEL_GDT ; GDT长度

GdtPtr dw GdtLen - 1 ; GDT界限

            dd 0 ; GDT基地址


; GDT 选择子

SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT

SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT

; END of [SECTION .gdt]


[SECTION .s16]

[BITS 16]

LABEL_BEGIN:

        mov ax, cs

        mov ds, ax

        mov es, ax

        mov ss, ax

        mov sp, 0100h   //栈顶指针寄存器

        ; 初始化 32 位代码段描述符

        xor eax, eax

        mov ax, cs

        shl eax, 4

        add eax, LABEL_SEG_CODE32                        //eax为 cs:LABEL_SEG_CODE32

        mov word [LABEL_DESC_CODE32 + 2], ax      //将LABEL_SEG_CODE32放到第二个字(也即3 4字节)

        shr eax, 16

        mov byte [LABEL_DESC_CODE32 + 4], al          //将al放到低字节

        mov byte [LABEL_DESC_CODE32 + 7], ah          //将ah放到高字节

        ; 为加载 GDTR 作准备

        xor eax, eax

        mov ax, ds

        shl eax, 4

        add eax, LABEL_GDT ; eax <- gdt 基地址

        mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址

        ; 加载 GDTR

        lgdt [GdtPtr]

        ; 关中断

        cli

        ; 打开地址线A20

        in al, 92h

        or al, 00000010b

        out 92h, al

        ; 准备切换到保护模式

        mov eax, cr0

        or eax, 1

        mov cr0, eax

        ; 真正进入保护模式

        jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs,

                                                        ; 并跳转到 Code32Selector:0  处

; END of [SECTION .s16]


[SECTION .s32]; 32 位代码段. 由实模式跳入.

[BITS 32]

LABEL_SEG_CODE32:

        mov ax, SelectorVideo

        mov gs, ax ; 视频段选择子(目的)

        mov edi, (80 * 11 + 79) * 2 ; 屏幕第 11 行, 第 79 列。

        mov ah, 0Ch ; 0000: 黑底    1100: 红字

        mov al, 'P'

        mov [gs:edi], ax

        ; 到此停止

        jmp $

SegCode32Len equ $ - LABEL_SEG_CODE32

; END of [SECTION .s32]


1.实模式

    Intel 8086 16位CPU,有16位的寄存器、16位的数据总线以及20位的地址总线(1MB的寻址能力)。

    物理地址 = 段地址 x 16 + 偏移

    此时段地址可以看做是地址的一部分。

2.保护模式

    Intel 80386进入32位时代,有32位地址总线(寻址空间可达4GB)。

    保护模式下段的概念发生了变化,段地址仍虽然由原来16位cs、ds寄存器表示,但此时它变成了一个索引,这个索引指向一个数据结构的一个表项,表项中详细定义了段的起始地址、界限、属性等。这个数据结构,就是GDT(LDT),GDT中的表项也有一个专门的名字,叫做描述符。

    GDT的作用是提供段式存储机制,这种机制是通过段寄存器和GDT中描述符共同提供的。

; 宏 ------------------------------------------------------------------------------------------------------

;

; 描述符

; usage: Descriptor Base, Limit, Attr

;            Base:  dd

;            Limit: dd (low 20 bits available)

;            Attr:  dw (lower 4 bits of higher byte are always 0)

%macro Descriptor 3

        dw      %2 & 0FFFFh                            ; 段界限1   //将limit的低16位放在最低0 1两个字节

        dw      %1 & 0FFFFh                            ; 段基址1   //将base的低16位放在2 3字节

        db      (%1 >> 16) & 0FFh                      ; 段基址2   //将base的第三位字节放在4字节

        dw      ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)    ; 属性1 + 段界限2 + 属性2  //按字节位置进行拼凑成 5 6字节

        db      (%1 >> 24) & 0FFh                      ; 段基址3   //将base的第四字节(从低位开始计数)放在7字节

%endmacro ; 共 8 字节

3.保护模式——段选择子(段选择符)

    段选择子包括三部分:描述符索引(index)、TI、请求特权级(RPL)。他的index(描述符索引)部分表示所需要的段的描述符在描述符表的位置,由这个位置再根据在GDTR中存储的描述符表基址就可以找到相应的描述符。然后用描述符表中的段基址加上逻辑地址(SEL:OFFSET)的OFFSET就可以转换成线性地址,段选择子中的TI值只有一位0或1,0代表选择子是在GDT选择,1代表选择子是在LDT选择。请求特权级(RPL)则代表选择子的特权级,共有4个特权级(0级、1级、2级、3级)。


    SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT  //  所需要的段的描述符在描述符表的位置

    mov ax, SelectorVideo

    mov gs, ax ; 视频段选择子(目的)      //段选择子(Selector)由GDTR访问全局描述符表是通过“段选择子”(实模式下的段寄存器)来完成的。段选择子是一个16位的寄存器(同实模式下的段寄存器相同),这里是寄存器gs


逻辑地址到线性地址的转换


    mov [gs:edi], ax   //gs的之为SelectorVideo,它对应显存的描述符DESC_VIDEO,这条指令将ax的值写入段DESC_VIDEO显存中偏移位edi的位置。

4.实模式到保护模式

step1.将描述符LABEL_DESC_CODE32初始化完成:将LABEL_SEG_CODE32的物理地址赋值给eax,并将它分成三部分赋值给描述符LABEL_DESC_CODE32中的相应位置。

step2.将GdtPtr指示的6字节加载到寄存器gdtr

    GdtLen equ $ - LABEL_GDT ; GDT长度

    GdtPtr dw GdtLen - 1 ; GDT界限

            dd 0 ; GDT基地址

    lgdt [GdtPtr]


step3.关中断,保护模式下中断处理机制是不同的

step4.打开A20地址线。A20地址不打开,只能寻址1MB

step5.将寄存器cr0的第0位置为1

    寄存器cr0的第0位是PE位,0-实模式,1-保护模式


step6.此时cs的值仍是实模式下的值,需要把代码段的选择子装入cs

    jmp dword SelectorCode32:0

    jmp dword ptr内存地址:以内存地址单元处的双字来修改指令,高地址内容修改CS,低地址内容修改IP,内存地址可以以任何合法的方式给出

    sudo ndisasm -o 0x7c00 pmtest1.bin >> wz.asm查看值

    00007C75  66EA000000000800  jmp dword 0x8:0x0   这里的SelectorCode32为8,赋值给cs

    bochs调试模式中,sreg可以看到cs的内容:

    cs:0x0008, dh=0x00409900, dl=0x7c800014, valid=1

    Code segment, base=0x00007c80, limit=0x00000014, Execute-Only, Non-Conforming, Accessed, 32-bit

5.描述符属性

LABEL_DESC_CODE32: Descriptor  0,                SegCode32Len - 1,    DA_C + DA_32; 非一致代码段

LABEL_DESC_VIDEO:  Descriptor      0B8000h,    0ffffh,                         DA_DRW     ; 显存首地址


DA_C            EQU    98h    ; 存在的只执行代码段属性值                       1001 1000

DA_32          EQU    4000h  ; 32 位段                                     100 0000 0000 0000

DA_DRW      EQU    92h    ; 存在的可读写数据段属性值                        1001 0010


dw      ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)    ; 属性1 + 段界限2 + 属性2  //按字节位置进行拼凑成 5 6字节

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容