• 由实模式进入保护模式


    代码取自《自己动手写操作系统》:

    pm.inc

    ; 描述符图示
    
    ; 图示一
    ;
    ;  ------ ┏━━┳━━┓高地址
    ;         ┃ 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  ┃ 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:    D位是一个很特殊的位,在描述可执行段、向下扩展数据段或由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                ; 段界限 1                (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

    ; ==========================================
    ; pmtest1.asm
    ; 编译方法:nasm pmtest1.asm -o pmtest1.com
    ; ==========================================
    
    %include    "pm.inc"    ; 常量, 宏, 以及一些说明
    
    org    0100h
        jmp    LABEL_BEGIN
    
    [SECTION .gdt]
    ; GDT
    ;                                         段基址,      段界限     , 属性
    LABEL_GDT:        Descriptor           0,                0, 0             ; 空描述符
    LABEL_DESC_CODE32:    Descriptor           0, SegCode32Len - 1, DA_C + DA_32    ; 非一致代码段, 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
        mov    word [LABEL_DESC_CODE32 + 2], ax
        shr    eax, 16
        mov    byte [LABEL_DESC_CODE32 + 4], al
        mov    byte [LABEL_DESC_CODE32 + 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] <- 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 * 10 + 0) * 2    ; 屏幕第 10 行, 第 0 列。
        mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
        mov    al, 'P'
        mov    [gs:edi], ax
    
        ; 到此停止
        jmp    $
    
    SegCode32Len    equ    $ - LABEL_SEG_CODE32
    ; END of [SECTION .s32]
  • 相关阅读:
    c/c++ 标准库 map multimap元素访问
    c/c++ 标准库 map set 删除
    c/c++ 标准库 map set 插入
    c/c++ 标准库 map set 大锅炖
    c/c++ 标准库 pair 介绍
    c/c++ 标准库 set 自定义关键字类型与比较函数
    c/c++ 标准库 插入迭代器 详解
    python基础-内置函数 isinstance() 与 issubclass()
    移动端事件(其他触摸事件)hammer.js
    移动端事件(touchstart+touchmove+touchend)
  • 原文地址:https://www.cnblogs.com/rixiang/p/5290657.html
Copyright © 2020-2023  润新知