保护模式详解

在ia32下,cpu有两种工作模式:实模式和保护模式。

在实模式下,16位的寄存器用“段+偏移”的方法计算有效地址。

段寄存器始终是16位的。在实模式下,段值xxxxh表示的以xxxx0h开始的一段内存。但在保护模式下,段寄存器的值变成了一个索引(还有附加信息)这个索引指向了一个数据结构的表(gdt/ldt)项,表项(描述符)中详细定义了段的其实地址、界限、属性等内容。

保护模式需要理解:描述符,选择子

描述符包括,存储段描述符(代码段,数据段,堆栈段),系统描述符(任务状态段TSS,局部描述符表LDT),门描述符(调用门,任务门,中断门,陷阱门),下面以存储段描述符位例

我们看一下描述符的结构:

描述符共8个字节:

0,1字节是段界限(2字节)

2,3,4字节是段基址的低24位(3字节)

5,6字节是段基址的属性(2字节)

7字节是段机制的高8位(1字节)

 

属性:

    (1) P:存在(Present)位。

    P=1 表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;

    P=0 表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。

    (2) DPL:  表示描述符特权级(Descriptor Privilege level),共2位。它规定了所描述段的特权级,用于特权检查,以决定对该段能否访问。 
    (3) DT:说明描述符的类型。
    对于存储段描述符而言,DT=1,以区别与系统段描述符和门描述符(DT=0)。 
    (4) TYPE: 说明存储段描述符所描述的存储段的具体属性。
    数据段类型 类型值说明
    ----------------------------------
    0只读 
    1只读、已访问 
    2读/写 
    3读/写、已访问 
    4只读、向下扩展 
    5只读、向下扩展、已访问 
    6读/写、向下扩展 
    7读/写、向下扩展、已访问 

 

选择子的结构:

 

RPL(Requested Privilege Level): 请求特权级,用于特权检查。
    TI(Table Indicator): 引用描述符表指示位
    TI=0 指示从全局描述符表GDT中读取描述符;
    TI=1 指示从局部描述符表LDT中读取描述符。

看一下段描述符的一个宏定义:


  1. ; 存储段描述符类型值说明  
  2. ;----------------------------------------------------------------------------  
  3. DA_DR       EQU 90h ; 存在的只读数据段类型值  1001 0000  
  4. DA_DRW      EQU 92h ; 存在的可读写数据段属性值 1001 0010  
  5. DA_DRWA     EQU 93h ; 存在的已访问可读写数据段类型值 1001 0011  
  6. DA_C        EQU 98h ; 存在的只执行代码段属性值 1001 1000  
  7. DA_CR       EQU 9Ah ; 存在的可执行可读代码段属性值 1001 1010  
  8. DA_CCO      EQU 9Ch ; 存在的只执行一致代码段属性值 1001 1100  
  9. DA_CCOR     EQU 9Eh ; 存在的可执行可读一致代码段属性值 1001 1110  


59
.; 宏 ------------------------------------------------------------------------------------------------------ 60.; 61.; 描述符 62.; usage: Descriptor Base, Limit, Attr 63.; Base: dd 64.; Limit: dd (low 20 bits available)低二十位可用 65.; Attr: dw (lower 4 bits of higher byte are always 0)高字节的低四位始终为0 66.%macro Descriptor 3 ;段界限为低地址 1代表Base 2代表Limit 3代表属性 67. dw %2 & 0FFFFh ; 段界限 1 (2 字节) 68. dw %1 & 0FFFFh ; 段首地址 1 (2 字节) 69. db (%1 >> 16) & 0FFh ; 段首地址 2 (1 字节) 70. dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 属性 1 + 段界限 2 + 属性 2 (2 字节) 71. db (%1 >> 24) & 0FFh ; 段首地址 3 (1 字节) 72.%endmacro ; 共 8 字节

base传递的是段基址:dd双字,32位

limit传递的是段界限:dd双子,但只会用到低20位    ((%2>>8)& 0f00h)

Attr传递的是属性:字16位,高字节的低4位会被抹去。(%3 & 0f0ffh)

 

gdtr寄存器格式:

 

 (1)准备gdt。

(2)加载gdt。

(3)关中断,保护模式下的中断处理方式是不同的,不关中断可能发生错误。

(4)打开a20地址线。

(5)置cr0的PE位。

(6)跳转进入保护模式。

 

 

实例:



; ┏━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┓
; ┃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 ┃
; ┗━━━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━┛
; 高地址 低地址
;
;
%macro Descriptor 3 ;base(dd) limit(dd) attr(dw)
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 字节


DA_32 EQU 4000h ; 32 位段
DA_DR EQU 90h ; 存在的只读数据段类型值
DA_DRW EQU 92h ; 存在的可读写数据段属性值


 



org 0100h
jmp LABEL_BEGIN


[SECTION .gdt]
;利用Descriptor 宏 base , limit ,attr
LABEL_GDT: Descriptor 0, 0, 0 ;空描述符
LABEL_DESC_32: Descriptor 0,CODE32_LEN-1,DA_32+DA_DR
LABEL_DESC_VEDIO Descriptor 0B8000h,0ffffh,DA_DRW
GDT_LEN EQU $-LABEL_GDT
GDTPTR dw GDT_LEN-1 ;gdt界限
dd 0
;GDT 选择子
SelectorCode32 equ LABEL_DESC_32 - LABEL_GDT
SelectorVedio equ LABEL_DESC_VEDIO - LABEL_GDT


[SECTION .c16]
[BITS 16]
LABEL_BEGIN:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0100h
;初始化gdt
xor eax,eax
mov ax,cs
shl eax,4
add eax,LABEL_SEC_CODE32
mov word [LABEL_DESC_32+2],ax
shr eax,16
mov byte [LABEL_DESC_32+4],al
mov byte [LABEL_DESC_32+7],ah
; 为加载 GDTR 作准备
xor eax,eax
mov ax,ds
shl eax,4
add eax,LABEL_GDT
mov dword [GDTPTR+2], eax
;加载gtd
lgtd [GDTPTR]
;关中断
cli
;打开a20地址线
in al,92h
or al,00000010h
out 92h,al
;cr0
mov eax,cr0
or eax,1
mov cr0,eax


;jmp
jmp dword SelectorCode32:0



LABEL_SEC_CODE32:
mov ax,SelectorCode32
mov gs,ax
mov edi, (80 * 10 + 0) * 2 ;10行0列
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov al,'P'
mov [gs:edi],ax


jmp $


CODE32_LEN EQU $-LABEL_SEC_CODE32

 

 

参考《自己动手写操作系统》

posted on 2014-05-26 19:30  andyhe  阅读(2173)  评论(0编辑  收藏  举报

导航