美文网首页
保护模式与实模式切换以及GDT(全局描述符表)

保护模式与实模式切换以及GDT(全局描述符表)

作者: 守拙圆 | 来源:发表于2017-12-21 07:09 被阅读41次
    ; 描述符图示
    
    ; 图示一
    ;
    ;  ------ ┏━━━┳━━━━━┓高地址
    ;         ┃ 7   段  ┃  
    ;         ┣━━━┫     ┃
    ;               基
    ;  字节 7 ┆   ┆     ┆
    ;               址
    ;         ┣━━━┫ ②   ┃
    ;         ┃ 0       ┃
    ;  ------ ┣━━━╋━━━━━┫
    ;         ┃ 7 ┃ G   ┃
    ;         ┣━━━╉━━━──┨
    ;         ┃ 6 ┃ D   ┃
    ;         ┣━━━╉━━━──┨
    ;         ┃ 5 ┃ 0   ┃
    ;         ┣━━━╉━━━──┨
    ;         ┃ 4 ┃ AVL ┃
    ;  字节 6 ┣━━━╉━━━──┨
    ;         ┃ 3 ┃     ┃
    ;         ┣━━━┫ 段  ┃
    ;         ┃ 2 ┃ 界  ┃
    ;         ┣━━━┫ 限  ┃
    ;         ┃ 1 ┃     ┃
    ;         ┣━━━┫ ②   ┃
    ;         ┃ 0 ┃     ┃
    ;  ------ ┣━━━╋━━━━━┫
    ;         ┃ 7 ┃ P   ┃
    ;         ┣━━━╉━━━──┨
    ;         ┃ 6 ┃     ┃
    ;         ┣━━━┫ DPL ┃
    ;         ┃ 5 ┃     ┃
    ;         ┣━━━╉━━━──┨
    ;         ┃ 4 ┃ S   ┃
    ;  字节 5 ┣━━━━╉━━──┨
    ;         ┃ 3  ┃    ┃
    ;         ┣━━━━┫ T  ┃
    ;         ┃ 2  ┃ Y  ┃
    ;         ┣━━━━┫ P  ┃
    ;         ┃ 1  ┃ E  ┃
    ;         ┣━━━━┫    ┃
    ;         ┃ 0  ┃    ┃
    ;  ------ ┣━━━━╋━━━━┫
    ;         ┃ 23 ┃    ┃
    ;         ┣━━━━┫    ┃
    ;         ┃ 22 ┃    ┃
    ;         ┣━━━━┫ 段 ┃
    ;
    ;   字节  ┆    ┆ 基 ┆
    ; 2, 3, 4
    ;         ┣━━━━┫ 址 ┃
    ;         ┃ 1  ┃ ①  ┃
    ;         ┣━━━━┫    ┃
    ;         ┃ 0  ┃    ┃
    ;  ------ ┣━━━━╋━━━━┫
    ;         ┃ 15 ┃    ┃
    ;         ┣━━━━┫    ┃
    ;         ┃ 14 ┃    ┃
    ;         ┣━━━━┫ 段 ┃
    ;
    ; 字节 0,1┆    ┆ 界 ┆
    ;
    ;         ┣━━━━┫ 限 ┃
    ;         ┃ 1  ┃ ①  ┃
    ;         ┣━━━━┫    ┃
    ;         ┃ 0  ┃    ┃
    ;  ------ ┗━━━━┻━━━━┛低地址
    ;
    
    
    ; 图示二
    
    ; 高地址………………………………………………………………………低地址
    
    ; |   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0    |
    ; |7654321076543210765432107654321076543210765432107654321076543210|    <- 共 8 字节
    ; |--------========--------========--------========--------========|
    ; ┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
    ; ┃31..24 ┃   (见下图)    ┃     段基址(23..0)      ┃ 段界限(15..0)   ┃
    ; ┃       ┃               ┃                       ┃                ┃
    ; ┃ 基址2 ┃ ③ │ ② │    ①  ┃ 基址1b │   基址1a      ┃    段界限1      ┃
    ; ┣━━━━━━━╋━━━━━━━┳━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━┫
    ; ┃   %6  ┃%5 ┃%4 ┃  %3   ┃     %2                ┃       %1       ┃
    ; ┗━━━┻━━━┻━━━┻━━━┻━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┛
    ;         │                \_________
    ;         │                          \__________________
    ;         │                                             \________________________________________________
    ;         │                                                                                              \
    ;         ┏━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┓
    ;         ┃ 7  ┃ 6  ┃ 5  ┃ 4  ┃ 3  ┃ 2  ┃ 1  ┃ 0  ┃ 7  ┃ 6  ┃ 5  ┃ 4  ┃ 3  ┃ 2  ┃ 1  ┃ 0  ┃
    ;         ┣━━━━╋━━━━╋━━━━╋━━━━╋━━━━┻━━━━┻━━━━┻━━━━╋━━━━╋━━━━┻━━━━╋━━━━╋━━━━┻━━━━┻━━━━┻━━━━┫
    ;         ┃ G  ┃D/B ┃ 0  ┃ AVL┃段界限 2 (19..16)  ┃  P ┃   DPL    ┃ S  ┃       TYPE       ┃
    ;         ┣━━━━┻━━━━┻━━━━┻━━━━╋━━━━━━━━━━━━━━━━━━╋━━━━┻━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━┫
    ;         ┃      ③: 属性 2    ┃    ②: 段界限 2    ┃                   ①: 属性1             ┃
    ;         ┗━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
    ;       高地址                                                                   低地址
    ;
    ;
    
    ; 说明:
    ;
    ; (1) P:   存在(Present)位。
    ;       P=1 表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;
    ;       P=0 表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。
    ;
    ; (2) DPL:  表示描述符特权级(Descriptor Privilege level),共2位。它规定了所描述段的特权级,
    ;           用于特权检查,以决定对该段能否访问。 
    ;
    ; (3) S:   说明描述符的类型。
    ;       对于存储段描述符而言,S=1,以区别与系统段描述符和门描述符(S=0)。 
    ;
    ; (4) TYPE: 说明存储段描述符所描述的存储段的具体属性。
    ;数据段类型  类型值     说明
    ;           ----------------------------------
    ;           0       只读 
    ;           1       只读、已访问 
    ;           2       读/写 
    ;           3       读/写、已访问 
    ;           4       只读、向下扩展 
    ;           5       只读、向下扩展、已访问 
    ;           6       读/写、向下扩展 
    ;           7       读/写、向下扩展、已访问 
    ;
    ;       
    ;代码段类型  类型值     说明
    ;       ----------------------------------
    ;           8       只执行 
    ;           9       只执行、已访问 
    ;           A       执行/读 
    ;           B       执行/读、已访问 
    ;           C       只执行、一致码段 
    ;           D       只执行、一致码段、已访问 
    ;           E       执行/读、一致码段 
    ;           F       执行/读、一致码段、已访问 
    ;
    ;       
    ;系统段类型  类型编码    说明
    ;           ----------------------------------
    ;           0       <未定义>
    ;           1       可用286TSS
    ;           2       LDT
    ;           3       忙的286TSS
    ;           4       286调用门
    ;           5       任务门
    ;           6       286中断门
    ;           7       286陷阱门
    ;           8       未定义
    ;           9       可用386TSS
    ;           A       <未定义>
    ;           B       忙的386TSS
    ;           C       386调用门
    ;           D       <未定义>
    ;           E       386中断门
    ;           F       386陷阱门
    ;
    ; (5) G:    段界限粒度(Granularity)位。
    ;       G=0 表示界限粒度为字节;
    ;       G=1 表示界限粒度为4K 字节。
    ;           注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。 
    ;
    ; (6) D/B:  此位是一个很特殊的位,在描述可执行段、向下扩展数据段或由SS寄存器寻址的段
    ;         (通常是堆栈段)的三种描述符中的意义各不相同。 
    ;      ⑴ 在描述可执行段的描述符中,D位决定了指令使用的地址及操作数所默认的大小。
    ;       ① D=1表示默认情况下指令使用32位地址及32位或8位操作数,这样的代码段也称为32位代码段;
    ;       ② D=0 表示默认情况下,使用16位地址及16位或8位操作数,这样的代码段也称为16位代码段,
    ;        它与80286兼容。可以使用地址大小前缀和操作数大小前缀分别改变默认的地址或操作数的大小。 
    ;      ⑵ 在向下扩展数据段的描述符中,D 位决定段的上部边界。
    ;       ① D=1表示段的上部界限为4G;
    ;       ② D=0表示段的上部界限为64K,这是为了与80286兼容。 
    ;      ⑶ 在描述由SS寄存器寻址的段描述符中,D位决定隐式的堆栈访问指令(如PUSH和POP指令)使用
    ;        何种堆栈指针寄存器。
    ;       ① D=1表示使用32位堆栈指针寄存器ESP;
    ;       ② D=0表示使用16位堆栈指针寄存器SP,这与80286兼容。 
    ;
    ; (7) AVL:  软件可利用位。80386对该位的使用未左规定,Intel公司也保证今后开发生产的处理器
    ;      只要与80386兼容,就不会对该位的使用做任何定义或规定。 
    ;
    
    
    ;----------------------------------------------------------------------------
    ; 描述符类型值说明
    ; 其中:
    ;       DA_  : Descriptor Attribute
    ;       D    : 数据段
    ;       C    : 代码段
    ;       S    : 系统段
    ;       R    : 只读
    ;       RW   : 读写
    ;       A    : 已访问
    ;       其它 : 可按照字面意思理解
    ;----------------------------------------------------------------------------
    DA_32       EQU 4000h   ; 32 位段
    
    DA_DPL0     EQU   00h   ; DPL = 0
    DA_DPL1     EQU   20h   ; DPL = 1
    DA_DPL2     EQU   40h   ; DPL = 2
    DA_DPL3     EQU   60h   ; DPL = 3
    ;----------------------------------------------------------------------------
    ; 存储段描述符类型值说明
    ;----------------------------------------------------------------------------
    DA_DR       EQU 90h ; 存在的只读数据段类型值
    DA_DRW      EQU 92h ; 存在的可读写数据段属性值
    DA_DRWA     EQU 93h ; 存在的已访问可读写数据段类型值
    DA_C        EQU 98h ; 存在的只执行代码段属性值
    DA_CR       EQU 9Ah ; 存在的可执行可读代码段属性值
    DA_CCO      EQU 9Ch ; 存在的只执行一致代码段属性值
    DA_CCOR     EQU 9Eh ; 存在的可执行可读一致代码段属性值
    ;----------------------------------------------------------------------------
    ; 系统段描述符类型值说明
    ;----------------------------------------------------------------------------
    DA_LDT      EQU   82h   ; 局部描述符表段类型值
    DA_TaskGate EQU   85h   ; 任务门类型值
    DA_386TSS   EQU   89h   ; 可用 386 任务状态段类型值
    DA_386CGate EQU   8Ch   ; 386 调用门类型值
    DA_386IGate EQU   8Eh   ; 386 中断门类型值
    DA_386TGate EQU   8Fh   ; 386 陷阱门类型值
    ;----------------------------------------------------------------------------
    
    
    ; 选择子图示:
    ;   ┏━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┳━━━━┓
    ;   ┃ 15 ┃ 14 ┃ 13 ┃ 12 ┃ 11 ┃ 10 ┃ 9  ┃ 8  ┃ 7  ┃ 6  ┃ 5  ┃ 4  ┃ 3  ┃ 2  ┃ 1  ┃ 0  ┃
    ;   ┣━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━┻━━━━╋━━━━╋━━━━┻━━━━┫
    ;   ┃                      描述符索引                                 ┃ TI ┃   RPL   ┃
    ;   ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━┛
    ;
    ; RPL(Requested Privilege Level): 请求特权级,用于特权检查。
    ;
    ; TI(Table Indicator): 引用描述符表指示位
    ;   TI=0 指示从全局描述符表GDT中读取描述符;
    ;   TI=1 指示从局部描述符表LDT中读取描述符。
    ;
    
    ;----------------------------------------------------------------------------
    ; 选择子类型值说明
    ; 其中:SA_  : Selector Attribute
    
    SA_RPL0     EQU 0   ; ┓
    SA_RPL1     EQU 1   ; ┣ RPL
    SA_RPL2     EQU 2   ; ┃
    SA_RPL3     EQU 3   ; ┛
    
    SA_TIG      EQU 0   ; ┓TI
    SA_TIL      EQU 4   ; ┛
    ;----------------------------------------------------------------------------
    
    
    ; 宏 ------------------------------------------------------------------------------------------------------
    ;
    ; 描述符
    ; 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             ; 段界限(2 字节)
        dw  %1 & 0FFFFh             ; 段基址1(2 字节)
        db  (%1 >> 16) & 0FFh           ; 段基址 2(1 字节)
        dw  ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性 1 + 段界限 2 + 属性 2(2 字节)
        db  (%1 >> 24) & 0FFh           ; 段基址 3(1 字节)
    %endmacro ; 共 8 字节
    ;
    ; 门
    ; usage: Gate Selector, Offset, DCount, Attr
    ;        Selector:  dw
    ;        Offset:    dd
    ;        DCount:    db
    ;        Attr:      db
    %macro Gate 4
        dw  (%2 & 0FFFFh)               ; 偏移 1  (2 字节)
        dw  %1                  ; 选择子(2 字节)
        dw  (%3 & 1Fh) | ((%4 << 8) & 0FF00h)   ; 属性(2 字节)
        dw  ((%2 >> 16) & 0FFFFh)           ; 偏移 2(2 字节)
    %endmacro ; 共 8 字节
    ; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    
    ; ===========================================================
    ; pmtest1.asm
    ; 编译方法:nasm pmtest1.asm -o pmtest1.bin
    ; ==========================================================
    
    %include "pm.inc"  ;定义一些常量,宏,以及一些说明
    
    org 0100h
    jmp LABEL_BEGIN
    
    [SECTION .gdt]
    ; GDT
    ;段基址,段界限,属性
    LABEL_GDT: Descriptor 0, 0, 0 ;空描述符
    LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ;normal 描述符
    LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32  ;非一致代码段
    LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C; 非一致代码段  16
    LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW ;data 
    LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32 ;Stack 32位
    LABEL_DESC_TEST: Descriptor 0500000h, 0ffffh, DA_DRW 
    LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ;显存首地址
    ; GDT 结束
    
    
    GdtLen equ $ - LABEL_GDT  ;GDT 的长度
    GdtPtr dw GdtLen - 1 ;GDT界限
    dd 0 ; GDT基地址
    
    ;GDT选择子
    SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
    SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
    SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
    SelectorData equ LABEL_DESC_DATA - LABEL_GDT
    SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
    SelectorTest equ LABEL_DESC_TEST - LABEL_GDT
    SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
    ;END of [SECTION .gdt]
    
    [SECTION .data1] ;数据段
    ALIGN 32
    [BITS 32]
    LABEL_DATA:
    SPValueInRealMode dw 0
    ;字符串
    PMMessage: db "In.Protect.Mode.now. ^-^", 0   ;在保护模式中显示
    OffsetPMMessage equ PMMessage - $$
    strTest: db "ABCDEFGGIJKLMNOPQRSTUVWXYZ", 0
    OffsetStrTest equ strTest - $$
    DataLen equ $ - LABEL_DATA 
    ; END of [Section .data1]
    
    ;全局堆栈段
    [SECTION .gs]
    ALIGN 32
    [BITS 32]
    LABEL_STACK:
    times 512 db 0
    TopOfStack equ $ - LABEL_STACK - 1
    ;end of [SECTION .gs]
    
    
    
    [SECTION .s16]
    [BITS 16]
    LABEL_BEGIN:
    mov ax, cs 
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0100h ;实模式下所用内存空间为64K(0100h),故指定最高地址为栈顶
    
    mov [LABEL_GO_BACK_TO_REAL + 3], ax 
    mov [SPValueInRealMode], sp 
    
    ;;初始化15位段描述符 
    mov ax, cs 
    movzx eax, ax 
    shl eax, 4
    add eax, LABEL_SEG_CODE16
    mov word [LABEL_DESC_CODE16 + 2], ax 
    shr eax, 16
    mov byte [LABEL_DESC_CODE16 + 4], al 
    mov byte [LABEL_DESC_CODE16 + 7], ah 
    
    ;;初始化32位代码段描述符
    xor eax, eax
    mov ax, cs
    shl eax, 4  ;此时处于实模式运行 其段基址与偏移的计算方式位 cs<<4 + offset
    add eax, LABEL_SEG_CODE32
    mov word [LABEL_DESC_CODE32 + 2], ax
    shr eax, 16
    mov byte [LABEL_DESC_CODE32 + 4], al
    mov byte [LABEL_DESC_CODE32 + 7], ah
    
    ;;初始化数据段描述符
    xor eax, eax 
    mov ax, ds 
    shl eax, 4
    add eax, LABEL_DATA 
    mov word [LABEL_DESC_DATA + 2], ax 
    shr eax, 16
    mov byte [LABEL_DESC_DATA + 4], al 
    mov byte [LABEL_DESC_DATA + 7], ah 
    
    ;;初始化堆栈描述符 
    xor eax, eax 
    mov ax, ds 
    shl eax, 4 
    add eax, LABEL_STACK 
    mov word [LABEL_DESC_STACK + 2], ax 
    shr eax, 16
    mov byte [LABEL_DESC_STACK + 4], al 
    mov byte [LABEL_DESC_STACK + 7], ah 
    
    ;;为加载GDTR做准备
    xor eax, eax
    mov ax, ds  
    shl eax, 4
    add eax, LABEL_GDT  ;eax <-gdt基地址
    mov dword [GdtPtr + 2], eax ; 将地址赋给GdtPtr高2个字节
    
    
    ;;加载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处,
    
    LABEL_REAL_ENTRY:
    mov ax, cs 
    mov ds, ax 
    mov es, ax 
    mov ss, ax 
    
    mov sp, [SPValueInRealMode]
    
    in al, 92h 
    or al, 11111101b
    out 92h, al 
    
    sti 
    
    mov ax, 4c00h 
    int 21h  ;;回到dos
    
    
    
    ;;END of [SECTION .s16]
    
    [SECTION .s32] ;;进入32位代码 由实模式跳入
    [BITS 32]
    
    LABEL_SEG_CODE32:
    mov ax, SelectorVideo
    mov gs, ax ;视频段选择子
    mov ax, SelectorTest
    mov es, ax 
    mov ax, SelectorData
    mov ds, ax 
    mov ax, SelectorStack
    mov ss, ax 
    
    mov esp, TopOfStack 
    
    ;下面显示一个字符
    mov ah, 0ch ;; 0000 黑底, 1100:红字
    xor esi, esi
    xor edi, edi 
    mov esi, OffsetPMMessage ;;源数据偏移
    mov edi (80*10 + 0) *2
    cld  ;;//清除方向标识,使其为 0
    .1:
    lodsb  ;;//将ds中si所指向的内容按字节加载到al中,由于方向标志为0,故si自动+1
    test al, al 
    jz .2
    mov [gs:edi], ax 
    add edi, 2
    jmp .1
    .2:  ;显示完毕
    
    call DispReturn
    
    call TestRead
    call TestWrite
    call TestRead
    
    
    ;;到此停止,再次跳转回 实模式
    jmp SelectCode16:0
    TestRead:
    xor esi, esi
    mov ecx, 8
    .loop:
    mov al, [es:esi]
    call DispAL
    inc esi
    loop .loop
    
    call DispReturn
    
    ret
    ;;Testread 结束
    
    TestWrite:
    push esi 
    push edi
    xor esi, esi
    xor edi, edi
    mov esi, OffsetStrTest ;;源数据
    cld 
    .1:
    lodsb
    test al, al 
    jz .2
    mov [es:edi], al 
    inc edi
    jmp .1
    .2:
    
    pop edi
    pop esi 
    
    ret
    ;;Testwrite 结束
    
    ;;
    ;;显示AL中的数字
    ;;默认地:
    ;;数字已经存在AL中
    ;;edi始终指向要显示的下一个字符的位置
    ;;被改变的寄存器 ax, edi 
    DispAL:
    push edx
    push ecx
    
    mov ah, 0ch 
    mov dl, al 
    shr al, 4
    mov ecx, 2
    .begin:
    and al, 01111b 
    cmp al, 9
    ja .1
    add al, '0'
    jmp .2
    .1:
    sub al, 0Ah
    add al, 'A'
    .2:
    mov [gs:edi], ax 
    add edi, 2
    mov al, dl 
    loop .begin
    add edi, 2
    
    pop edx 
    pop ecx 
    ret
    ;;DispAL 结束
    
    DispReturn:
    push eax 
    push ebx 
    mov eax, edi
    mov bl, 160
    div bl 
    and eax, 0ffh 
    inc eax 
    mov bl, 160
    mul bl 
    mov edi, eax 
    pop ebx 
    pop eax 
    
    ret
    ;;Dispreturn 结束
    
    
    
    
    ;mov edi, (80 * 11 + 79) * 2 
    ;mov ah, 0ch 
    ;mov al, 'D'
    ;mov [gs:edi], ax
    
    ;;end
    jmp $
    
    SegCode32Len equ $ - LABEL_SEG_CODE32
    ;;end of [SECTION .s32]
    
    
    ;;16位代码段,由32位跳入,从而进入实模式
    [SECTION .s16code]
    ALIGN 32 
    [BITS 16]
    LABEL_SEG_CODE16:
    mov ax, SelectorNormal 
    mov ds, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 
    mov ss, ax 
    
    mov eax, cr0 
    and al, 11111110b 
    mov cr0, eax 
    
    LABEL_GO_BACK_TO_REAL:
    jmp 0:LABEL_REAL_ENTRY 
    
    Code16Len equ $-LABEL_SEG_CODE16
    

    保护模式与实模式跳转的步骤:

    1. BIOS完成后,程序到0100h处执行,接着跳转到16位代码段进行执行(注意此时 cs为实模式下16位代码段基址),在16位dos实模式下堆栈初始化位置位0100h。接下来进行数据段,代码段,堆栈段,段描述符的初始化工作。
    2. 此处为后面从保护模式跳转回实模式的一步关键准备工作:mov [LABEL_GO_BACK_TO_REAL + 3], ax ; mov [SPValueInRealMode], sp 此处将LABEL_GO_BACK_TO_REAL 标签后第3字节开始,填充位实模式的代码段基址。并保存堆栈地址。
    3. 打开地址线 A20,设置保护模式开启位
    4. 跳转进入保护模式,jmp dword SelectorCode32:0
    5. 实模式完成显示任务
    6. 执行'jmp SelectCode:0'跳转到16位的保护模式到实模式过渡代码段(.s16code)执行。
    7. 此处注意mov ax, SelectorNormal的作用为:因为保护模式下GDT的高速缓冲寄存器中内容必须进行清理,这里利用SelectorNormal将GDT的高速缓冲寄存器中内容替换为实模式下中的内容,注意:实模式下所有段的fffffh--00000h,且读写属性应该为可读写。
      8.由于jmp的跳转地址已经在步骤2中改写为实模式下代码段的基址。

    代码中有几点需要注意的地方:

    org 0100h

    org不是操作符而是编译时的标记,最终的二进制代码中并不存在此操作符。该标记粗略来说有两个作用:

    • 指定程序的加载到内存的实际开始地址
    • 指明对于程序中的常量要进行相对编址(例如:若加org,常量字符串位于 org + offset;若不加 org,则常量字符串的编址为 0 + offset)

    初始化GDT描述符基址的方法

    xor eax, eax  ;清除eax
    mov ax, ds  ;此时 ds 为实模式下代码段基址
    shl eax, 4   ;此时处于实模式运行 其段基址与偏移的计算方式位 cs<<4 + offset
    add eax, LABEL_DATA  ;此处为offset
    mov word [LABEL_DESC_DATA + 2], ax  ;将基址的0-15位赋予GDT的2,3字节
    shr eax, 16 ;将基址右移16位,ax变为基址的3,4字节
    mov byte [LABEL_DESC_DATA + 4], al 
    mov byte [LABEL_DESC_DATA + 7], ah 
    

    相关文章

      网友评论

          本文标题:保护模式与实模式切换以及GDT(全局描述符表)

          本文链接:https://www.haomeiwen.com/subject/tgiwwxtx.html