分段机制

出处:http://blog.csdn.net/h_armony/article/details/9751605


先对分段机制中必须用到的一些名词作一个解释:

段选择符:又称端选择子,是段的一个16位标识符。它并不直接指向段,而是指向段选择符表中定义段的段描述符。它有三个字段内容:请求特权级RPL(Request Privilege Level)、表指示标志TI(Table Index)、索引值(Index)


段描述符:段描述符石GDT和LDT表中的一个数据结构项,用来向处理器提供一个有关段的位置和大小信息以及访问控制的状态信息。包含三个主要字段:段基地址、段限长、和段属性。段描述符通常由编译器、连接器、加载器或者操作系统来创建。


段描述符表: 是段描述符的一个数组。


接下来看一下适用分段机制将逻辑地址转化为线性地址的步骤:

1)使用段选择符中的偏移值(段索引)在GDT或LDT表中定位相应的段描述符.(仅当一个新的段选择符加载到段寄存器中是才需要这一步)

2)利用段选择符检验段的访问权限和范围,以确保该段可访问。

3)把段描述符中取到的段基地址加到偏移量上,最后形成一个线性地址。

从《一个操作系统的实现》的源码来理解分段机制:

[cpp]  view plain copy
  1. org 07c00h                                
  2.     jmp LABEL_BEGIN  
  3.   
  4. [SECTION .gdt]  
  5. ; GDT  
  6. ;                              段基址,       段界限     , 属性  
  7. LABEL_GDT:     Descriptor       0,                0, 0           ; 空描述符  
  8. LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段  
  9. LABEL_DESC_LDT:    Descriptor       0,        LDTLen - 1, DA_LDT    ; LDT  
  10. LABEL_DESC_VIDEO:  Descriptor 0B8000h,           0ffffh, DA_DRW      ; 显存首地址  
  11. ; GDT 结束  
  12.   
  13. GdtLen      equ $ - LABEL_GDT   ; GDT长度  
  14. GdtPtr      dw  GdtLen - 1  ; GDT界限  
  15.         dd  0       ; GDT基地址  
  16.   
  17. ; GDT 选择子  
  18. SelectorCode32      equ LABEL_DESC_CODE32   - LABEL_GDT  
  19. SelectorLDT     equ LABEL_DESC_LDT      - LABEL_GDT  
  20. SelectorVideo       equ LABEL_DESC_VIDEO    - LABEL_GDT   
  21. ; END of [SECTION .gdt]  
  22.   
  23. [SECTION .s16]  
  24. [BITS   16]  
  25. LABEL_BEGIN:  
  26.     mov ax, cs  
  27.     mov ds, ax  
  28.     mov es, ax  
  29.     mov ss, ax  
  30.     mov sp, 0100h  
  31.   
  32.     ; a)初始化 32 位代码段描述符  
  33.     xor eax, eax  
  34.     mov ax, cs                             ;把代码段基地址内容赋值给ax  
  35.     shl eax, 4                             ;左移4为相当与*16  
  36.     add eax, LABEL_SEG_CODE32              ;把加上段相对代码段的偏移地址,等于段的基地址  
  37.     mov word [LABEL_DESC_CODE32 + 2], ax   ;将该基地址分别填充到段描述符的 2 3 4 7字节上去  
  38.     shr eax, 16  
  39.     mov byte [LABEL_DESC_CODE32 + 4], al  
  40.     mov byte [LABEL_DESC_CODE32 + 7], ah  
  41.   
  42.     ; 初始化 LDT 在 GDT 中的描述符             L1)为了从全局描述符表中找到局部描述符表在内存中的地址  
  43.     xor eax, eax  
  44.     mov ax, ds  
  45.     shl eax, 4  
  46.     add eax, LABEL_LDT  
  47.     mov word [LABEL_DESC_LDT + 2], ax  
  48.     shr eax, 16  
  49.     mov byte [LABEL_DESC_LDT + 4], al  
  50.     mov byte [LABEL_DESC_LDT + 7], ah  
  51.   
  52.     ; 初始化 LDT 中的描述符                    L2)再从局部描述符表中找到相应段在内存中的地址  
  53.     xor eax, eax  
  54.     mov ax, ds  
  55.     shl eax, 4  
  56.     add eax, LABEL_CODE_A  
  57.     mov word [LABEL_LDT_DESC_CODEA + 2], ax  
  58.     shr eax, 16  
  59.     mov byte [LABEL_LDT_DESC_CODEA + 4], al  
  60.     mov byte [LABEL_LDT_DESC_CODEA + 7], ah  
  61.               
  62.     ; b)为加载 GDTR 作准备  
  63.     xor eax, eax  
  64.     mov ax, ds  
  65.     shl eax, 4  
  66.     add eax, LABEL_GDT      ; eax <- gdt 基地址  
  67.     mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址  
  68.   
  69.     ; c)加载 GDTR  
  70.     lgdt    [GdtPtr]      
  71.                           
  72.     ; d)关中断  
  73.     cli  
  74.   
  75.     ; e)打开地址线A20  
  76.     in  al, 92h                               
  77.     or  al, 00000010b  
  78.     out 92h, al                               
  79.   
  80.     ; f)准备切换到保护模式  
  81.     mov eax, cr0  
  82.     or  eax, 1  
  83.     mov cr0, eax  
  84.   
  85.     ; g)真正进入保护模式  
  86.     jmp dword SelectorCode32:0  ; 执行这一句会把 SelectorCode32 装入 cs,   
  87.                     ; 并跳转到 Code32Selector:0  处  
  88. ; END of [SECTION .s16]  
  89.   
  90.   
  91. [SECTION .s32]; 32 位代码段. 由实模式跳入.  
  92. [BITS   32]  
  93.   
  94. LABEL_SEG_CODE32:  
  95.     mov ax, SelectorVideo                     
  96.     mov gs, ax          ; 视频段选择子(目的)        1)把SelectorVideo段段选择子加载到段寄存器gs中  
  97.   
  98.     mov edi, (80 * 11 + 79) * 2 ; 屏幕第 11 行, 第 79 列。  
  99.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  100.     mov al, 'P'  
  101.     mov [gs:edi], ax        ;3)根据段选择子在GDT中找到相应的段描述符,获得段基地址,再加上偏移量,就得到了实际物理地址,把数据写入该地址,这里是把数据写到显存中             
  102.     jmp SelectorLDTCodeA:0  ; L3)跳入局部任务   
  103.   
  104.     ; 到此停止  
  105.     jmp $  
  106.   
  107. SegCode32Len    equ $ - LABEL_SEG_CODE32  
  108. ; END of [SECTION .s32]  
  109.   
  110. ; LDT  
  111. [SECTION .ldt]  
  112. ALIGN   32  
  113. LABEL_LDT:  
  114. ;                            段基址       段界限      属性  
  115. LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位  
  116.   
  117. LDTLen      equ $ - LABEL_LDT  
  118.   
  119. ; LDT 选择子  
  120. SelectorLDTCodeA    equ LABEL_LDT_DESC_CODEA    - LABEL_LDT + SA_TIL  
  121. ; END of [SECTION .ldt]  
  122.   
  123.   
  124. ; CodeA (LDT, 32 位代码段)  
  125. [SECTION .la]  
  126. ALIGN   32  
  127. [BITS   32]  
  128. LABEL_CODE_A:  
  129.     mov ax, SelectorVideo  
  130.     mov gs, ax          ; 视频段选择子(目的)  
  131.   
  132.     mov edi, (80 * 12 + 0) * 2  ; 屏幕第 10 行, 第 0 列。  
  133.     mov ah, 0Ch         ; 0000: 黑底    1100: 红字  
  134.     mov al, 'L'  
  135.     mov [gs:edi], ax  
  136.   
  137.     ; 准备经由16位代码段跳回实模式  
  138.     jmp SelectorCode16:0  
  139. CodeALen    equ $ - LABEL_CODE_A  
  140. ; END of [SECTION .la]  


可以看到最终得到物理地址并写数据需一行代码,但是前面需要做许多准备工作:a、b、c、d、e、f、g。具体内容看代码和批注。

上面讲到的是加载全局描述符表GDT,但是还有一个局部描述符表LDT没有涉及,那么LDT和GDT有什么区别呢,从上面代码上可以看到,LDT可以看做是GDT中的一个段,不过这个段里的内容是一张段描述符表。这两张表的关系如下图:


整个虚拟地址空间共含有2^14个段(段选择子索引值为12位,不是应该只有2^12个段吗?),一半空间由GDT映射,另一般则由LDT映射。GDT所映射的一半虚拟地址空间是系统所有任务共有的,而LDT映射的另一半则在任务切换时被改变(这应该就是内核空间与用户空间的概念吧)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值