操作系统-保护模式中的特权级(中)

Q:如何在不同特权级代码段之间跳转执行?
A.一种新的描述符,门描述符
1.通过门描述符在不同的特权级的代码间进行跳转
2.根据应用场景的不同,门描述符分为-调用门、中断门、陷阱门、任务门
B.门描述符的内存结构(与段描述符相似)
1.每一个门描述符占用8字节内存
2.不同类型门描述的内存含义不同
操作系统-保护模式中的特权级(中)
C.调用门描述符的定义
操作系统-保护模式中的特权级(中)
调用门描述符的工作原理
操作系统-保护模式中的特权级(中)
调用门描述符的使用
操作系统-保护模式中的特权级(中)
操作系统-保护模式中的特权级(中)
在这里需要注意的是汇编语言中的跳转方式
1.段内跳转:call,jmp-参数为相对地址,函数调用时只需要保存当前偏移地址
2.段间跳转:call for,jmp for-参数为选择子和偏移地址,函数调用时需要保存段基地址和偏移地址
调用门实验-如上图所示,将两个寄存器进行相加减运算
代码


%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 段基址,       段界限,       段属性
GDT_ENTRY       :     Descriptor    0,            0,           0
CODE32_DESC     :     Descriptor    0,    Code32SegLen - 1,    DA_C + DA_32
VIDEO_DESC      :     Descriptor 0xB8000,     0x07FFF,         DA_DRWA + DA_32
STACK32_DESC    :     Descriptor    0,     TopOfStack32,       DA_DRW + DA_32
FUNCTION_DESC   :     Descriptor    0,   FunctionSegLen - 1,   DA_C + DA_32
; Gate Descriptor 调用门
; Call Gate                        选择子,         偏移,      参数个数,      属性
FUNC_CG_ADD_DESC      Gate   FunctionSelector,   CG_Add,        0,      DA_386CGate
FUNC_CG_SUB_DESC      Gate   FunctionSelector,   CG_Sub,        0,      DA_386CGate
; GDT end

GdtLen    equ   $ - GDT_ENTRY

GdtPtr:
          dw   GdtLen - 1
          dd   0

; GDT Selector

Code32Selector     equ (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector      equ (0x0002 << 3) + SA_TIG + SA_RPL0
Stack32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
FunctionSelector   equ (0x0004 << 3) + SA_TIG + SA_RPL0
FuncCGAddSelector  equ (0x0005 << 3) + SA_TIG + SA_RPL0
FuncCGSubSelector  equ (0x0006 << 3) + SA_TIG + SA_RPL0

; end of [section .gdt]

TopOfStack16    equ 0x7c00

[section .s16]
[bits 16]
ENTRY_SEGMENT:
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, TopOfStack16

    ; initialize GDT for 32 bits code segment
    mov esi, CODE32_SEGMENT
    mov edi, CODE32_DESC

    call InitDescItem

    mov esi, STACK32_SEGMENT
    mov edi, STACK32_DESC

    call InitDescItem;初始化

    mov esi, FUNCTION_SEGMENT
    mov edi, FUNCTION_DESC

    call InitDescItem

    ; initialize GDT pointer struct
    mov eax, 0
    mov ax, ds
    shl eax, 4
    add eax, GDT_ENTRY
    mov dword [GdtPtr + 2], eax

    ; 1. load GDT
    lgdt [GdtPtr]

    ; 2. close interrupt
    cli 

    ; 3. open A20
    in al, 0x92
    or al, 00000010b
    out 0x92, al

    ; 4. enter protect mode
    mov eax, cr0
    or eax, 0x01
    mov cr0, eax

    ; 5. jump to 32 bits code
    jmp dword Code32Selector : 0;进入保护模式,跳转到CODE32_SEGMENT进入死循环 

; esi    --> code segment label
; edi    --> descriptor label
InitDescItem:
    push eax

    mov eax, 0
    mov ax, cs
    shl eax, 4
    add eax, esi
    mov word [edi + 2], ax
    shr eax, 16
    mov byte [edi + 4], al
    mov byte [edi + 7], ah

    pop eax

    ret

[section .s32]
[bits 32]
CODE32_SEGMENT:
    mov ax, VideoSelector
    mov gs, ax

    mov ax, Stack32Selector
    mov ss, ax

    mov eax, TopOfStack32
    mov esp, eax

    mov ax, 2
    mov bx, 1

    call FuncCGAddSelector : 0
    call FuncCGSubSelector : 0

    jmp $

Code32SegLen    equ    $ - CODE32_SEGMENT

[section .func];代码段 32位
[bits 32]
FUNCTION_SEGMENT:

; ax --> a
; bx --> b
; 
; return:
;     cx --> a + b
AddFunc:
    mov cx, ax;加法函数,寄存器相加
    add cx, bx
    retf;使用远调用

CG_Add    equ    AddFunc - $$;计算段内的偏移 

; ax --> a
; bx --> b
; 
; return:
;     cx --> a - b
SubFunc:
    mov cx, ax;减法函数,寄存器相减
    sub cx, bx
    retf

CG_Sub    equ    SubFunc - $$;计算段内的偏移  

FunctionSegLen   equ  $ - FUNCTION_SEGMENT

[section .gs]
[bits 32]
STACK32_SEGMENT:
    times 1024 * 4 db 0

Stack32SegLen equ $ - STACK32_SEGMENT
TopOfStack32  equ Stack32SegLen - 1

inc.sam 文件需要修改的是


; Segment Attribute
DA_32    equ    0x4000
DA_DR    equ    0x90
DA_DRW   equ    0x92
DA_DRWA  equ    0x93
DA_C     equ    0x98
DA_CR    equ    0x9A
DA_CCO   equ    0x9C
DA_CCOR  equ    0x9E

; Segment Privilege
DA_DPL0     equ   0x00    ; DPL = 0
DA_DPL1     equ   0x20    ; DPL = 1
DA_DPL2     equ   0x40    ; DPL = 2
DA_DPL3     equ   0x60    ; DPL = 3

; Special Attribute
DA_LDT       equ    0x82
DA_TaskGate  equ    0x85    ; 任务门类型值
DA_386TSS    equ    0x89    ; 可用 386 任务状态段类型值
DA_386CGate  equ    0x8C    ; 386 调用门类型值
DA_386IGate  equ    0x8E    ; 386 中断门类型值
DA_386TGate  equ    0x8F    ; 386 陷阱门类型值

; Selector Attribute
SA_RPL0    equ    0
SA_RPL1    equ    1
SA_RPL2    equ    2
SA_RPL3    equ    3

SA_TIG    equ    0
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 & 0xFFFF                         ; 段界限1
    dw    %1 & 0xFFFF                         ; 段基址1
    db    (%1 >> 16) & 0xFF                   ; 段基址2
    dw    ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
    db    (%1 >> 24) & 0xFF                   ; 段基址3
%endmacro                                     ; 共 8 字节

; 门
; usage: Gate Selector, Offset, DCount, Attr
;        Selector:  dw
;        Offset:    dd
;        DCount:    db
;        Attr:      db
%macro Gate 4
    dw    (%2 & 0xFFFF)                      ; 偏移地址1
    dw    %1                                 ; 选择子
    dw    (%3 & 0x1F) | ((%4 << 8) & 0xFF00) ; 属性
    dw    ((%2 >> 16) & 0xFFFF)              ; 偏移地址2
%endmacro 

实验定义两个功能函数,并使其两个寄存器的值进行相加减,主要核心代码如下

AddFunc:
    mov cx, ax;加法函数,寄存器相加
    add cx, bx
    retf;使用远调用

CG_Add    equ    AddFunc - $$;计算段内的偏移 

; ax --> a
; bx --> b
; 
; return:
;     cx --> a - b
SubFunc:
    mov cx, ax;减法函数,寄存器相减
    sub cx, bx
    retf

CG_Sub    equ    SubFunc - $$;计算段内的偏移  

实验结果如图所示
操作系统-保护模式中的特权级(中)操作系统-保护模式中的特权级(中)操作系统-保护模式中的特权级(中)操作系统-保护模式中的特权级(中)操作系统-保护模式中的特权级(中)
实验过程
1.首先通过反编译找到关键的跳转命令,如图该命令的地址位0x90aa
2.接下来进入bochs下设置断点,并查看断点是否设置成功
3.接下来单步调试,发现代码成功跳转到[section .s32] [bits 32]中执行,通过代码可知当其跳转到call FuncCGAddSelector : 0该语句时,会跳转到定义的加减法功能中
4.在这里首先查看各个寄存器的值,发现在没有进行加法计算时,ax寄存器的值位2,bx寄存器的值为1,而此时的cx寄存器的值为15
5.在进入到定义的功能函数中,继续单步执行,当其执行完毕,跳转到[section .s32] [bits 32]中时,此时加法计算完毕,此时查看寄存器的值,如图所示,此时ax寄存器的值位2,bx寄存器的值为1,而此时的cx寄存器的值为3
说明call FuncCGAddSelector该函数是一个指针,指向Add函数
实验总结
1.门描述符是一种特殊的描述符,需要注册于段描述符表
2.调用门可以看作一个函数指针(保存具体函数的入口地址)
3.通过调用门选择子对相应的函数进行远调用
4.可以直接选择使用选择子:偏移地址的方式调用其它段的函数
5.使用调用门时偏移地址无意义

猜你喜欢

转载自blog.51cto.com/13475106/2489130
今日推荐