“Global Descriptor Table”的版本间差异

来自osdev
跳到导航 跳到搜索
 
第1行: 第1行:
'''全局描述符表'''('''Global Descriptor Table - GDT''')是特定于[[IA32_Architecture_Family|IA-32]]和[[X86-64|x86-64]]体系结构的二进制数据结构。 它包含告诉CPU有关内存[[Segmentation|分段]]的条目。 还存在一个类似的 [[Interrupt Descriptor Table|中断描述符表(Interrupt Descriptor Table)]],其中包含 [[task|任务]] 和 [[Interrupts|中断]] 描述符。
'''全局描述符表'''('''Global Descriptor Table - GDT''')是特定于[[IA32_Architecture_Family|IA-32]]和[[X86-64|x86-64]]体系结构的二进制数据结构。 它包含告诉CPU有关内存[[Segmentation|分段]]的条目(Entry)。 还存在一个类似的 [[Interrupt Descriptor Table|中断描述符表(Interrupt Descriptor Table)]],其中包含 [[task|任务]] 和 [[Interrupts|中断]] 描述符。


建议阅读[[GDT Tutorial|GDT教程]]。
建议阅读[[GDT Tutorial|GDT教程]]。
第94行: 第94行:
* '''DPL:''' 描述符特权级别字段。 包含段的[[Security#Rings| CPU特权级别]] '''0''' =最高权限(内核),'''3''' = 最低权限(用户应用程序)。
* '''DPL:''' 描述符特权级别字段。 包含段的[[Security#Rings| CPU特权级别]] '''0''' =最高权限(内核),'''3''' = 最低权限(用户应用程序)。
* '''S:''' 描述符类型位。 如果清 ('''0'''),则描述符定义一个系统段 (例如 [[Task_State_Segment|任务状态段-Task State Segment]])。 如果设('''1'''),则定义代码或数据段。
* '''S:''' 描述符类型位。 如果清 ('''0'''),则描述符定义一个系统段 (例如 [[Task_State_Segment|任务状态段-Task State Segment]])。 如果设('''1'''),则定义代码或数据段。
* '''E:''' Executable(可执行)位。 如果清('''0'''),则描述符定义数据段。 如果设('''1'''),它定义了一个可以用于执行的代码段。
* '''E:''' Executable(可执行)位。 如果清('''0'''),则描述符定义数据段。 如果设('''1'''),它定义了一个可以用于执行的代码段。
* '''DC:''' Direction bit/Conforming 位。
* '''DC:''' Direction位/Conforming位。
** 对于数据(Data)选择器:  Direction 位。 如果清('''0'''),则该段将向上增长。 如果设('''1''')段[[Expand_Down|向下增长]],即'''Offset'''必须大于'''Limit'''。
** 对于数据(Data)选择器:  Direction 位。 如果清('''0'''),则该段将向上增长。 如果设('''1''')段[[Expand_Down|向下增长]],即'''Offset'''必须大于'''Limit'''。
** 对于代码(Code)选择器:Conforming 位。
** 对于代码(Code)选择器:Conforming 位。
*** 如果清('''0''')该段中的代码只能从'''Privl'''中设置的Ring执行。
*** 如果清('''0''')该段中的代码只能从'''Privl'''中设置的Ring执行。
*** 如果设('''1'''),此段可以从相等或较低的特权级别执行代码。 例如,Ring3中的代码可以跳转到Ring2段中的''conforming''代码。 '''Privl'''字段表示允许执行该段的最高权限级别。 例如,Ring0中的代码不能far-jump到 '''Privl''' 为2的conforming代码段,而ring2和ring中的代码可以。  请注意,跳转后特权级别保持不变,即从Ring3到'''Privl'''为2的段的far-jump仍保留在Ring3中。
*** 如果设('''1'''),此段可以从相等或较低的特权级别执行代码。 例如,Ring3中的代码可以跳转到Ring2段中的''conforming''代码。 '''Privl'''字段表示允许执行该段的最高权限级别。 例如,Ring0中的代码不能far-jump到 '''Privl''' 为2的conforming代码段,而ring2和ring中的代码可以。  请注意,跳转后特权级别保持不变,即从Ring3到'''Privl'''为2的段的far-jump仍保留在Ring3中。
* '''RW: ''' 可读位/可写位。
* '''RW: ''' 可读位/可写位。
** 对于代码段:可读位。 如果清('''0'''),则不允许对此段进行读取访问。 如果设('''1'''),则允许读取访问。 永远不允许对代码段进行写访问。
** 对于代码段:可读位。 如果清('''0'''),则不允许对此段进行读取访问。 如果设('''1'''),则允许读取访问。 永远不允许对代码段进行写访问。
** 对于数据段:可写位。 如果清 ('''0'''),则不允许对此段进行写访问。 如果设('''1'''),则允许写访问。 数据段始终允许读取访问。
** 对于数据段:可写位。 如果清 ('''0'''),则不允许对此段进行写访问。 如果设('''1'''),则允许写访问。 数据段始终允许读取访问。
* '''A:''' Accessed(已访问)位。 最好清('''0'''),CPU将在访问段时设它为1。
* '''A:''' Accessed(已访问)位。 最好清('''0'''),CPU将在访问段时设它为1。


{| class="wikitable"
{| class="wikitable"
第119行: 第119行:
* '''G:''' 粒度(Granularity )标志,指示'''Limit'''值的缩放大小。 如果清 ('''0'''),则 '''Limit''' 以1字节块为单位 (字节粒度)。 如果设('''1'''),'''Limit'''单位是4KiB块(页面粒度)。
* '''G:''' 粒度(Granularity )标志,指示'''Limit'''值的缩放大小。 如果清 ('''0'''),则 '''Limit''' 以1字节块为单位 (字节粒度)。 如果设('''1'''),'''Limit'''单位是4KiB块(页面粒度)。
* '''DB:''' Size标志。 如果清('''0'''),则描述符定义一个16位保护模式的段。 如果设 ('''1'''),它定义了一个32位受保护模式的段。 GDT可以同时具有16位和32位选择器。
* '''DB:''' Size标志。 如果清('''0'''),则描述符定义一个16位保护模式的段。 如果设 ('''1'''),它定义了一个32位受保护模式的段。 GDT可以同时具有16位和32位选择器。
* '''L:''' 长模式代码标志。 如果设('''1'''),则描述符定义64位代码段。 当它设1时,'''Sz''' 应始终清0。 对于任何其他类型的段(其他代码类型或任何数据段),它应该要清('''0''')。
* '''L:''' 长模式代码标志。 如果设('''1'''),则描述符定义64位代码段。 当它设1时,'''Sz''' 应始终清0。 对于任何其它类型的段(其它代码类型或任何数据段),它应该要清('''0''')。


==系统段描述符(System Segment Descriptor)==
==系统段描述符(System Segment Descriptor)==
第196行: 第196行:
* [[GDT Tutorial|GDT教程]]
* [[GDT Tutorial|GDT教程]]
*[[Getting to Ring 3|到达Ring 3]]
*[[Getting to Ring 3|到达Ring 3]]
*[[Segmentation|]]
*[[Segmentation|分段]]
* http://www.osdever.net/tutorials/view/the-world-of-protected-mode - how to set up GDT in assembler
* http://www.osdever.net/tutorials/view/the-world-of-protected-mode - how to set up GDT in assembler



2022年3月7日 (一) 13:15的最新版本

全局描述符表Global Descriptor Table - GDT)是特定于IA-32x86-64体系结构的二进制数据结构。 它包含告诉CPU有关内存分段的条目(Entry)。 还存在一个类似的 中断描述符表(Interrupt Descriptor Table),其中包含 任务中断 描述符。

建议阅读GDT教程

GDTR寄存器

GDTGDTR寄存器中的值指向。 这是使用LGDT汇编指令加载的,该指令的参数是指向GDT描述符结构的指针:

GDT Descriptor (GDTR)
79 (64-bit mode)
48 (32-bit mode)   16
15   0
Offset
63 (64-bit mode)
31 (32-bit mode)   0
Size

15   0
  • Size: 表的大小(以字节为单位)减去1。 之所以发生这种减法,是因为 size 的最大值是65535的,而GDT的长度最多可达65536个字节 (8192个条目)。 此外,gdt不可以具有0字节的大小。
  • Offset: GDT的线性地址(不是物理地址,分页适用)。

请注意,LGDT加载的数据量在32位和64位模式中不同,offset在32位模式中为4字节长,在64位模式中为8字节长。

有关更多信息,请参阅《英特尔软件开发人员手册》 (第3-A卷) 的 Section 2.4.1: Global Descriptor Table Register (GDTR)Figure 2-6: Memory Management Registers

表说明

GDT中的条目长度为8字节,形成如下表格:

Global Descriptor Table
地址 内容
GDTR Offset + 0 Null
GDTR Offset + 8 Entry 1
GDTR Offset + 16 Entry 2
GDTR Offset + 24 Entry 3
... ...

GDT (条目0) 中的第一个条目应始终为null,只使用后续条目。

表中的条目由段选择器(Segment Selectors)访问,这些条目通过汇编指令或硬件功能(如中断)加载到寄存器中。

段描述符(Segment Descriptor)

上面表中的每个条目(Entry)都有一个复杂的结构:

Segment Descriptor
63   56 55   52 51   48 47   40 39   32
Base
31   24
Flags
3   0
Limit
19   16
Access Byte
7   0
Base
23   16
31   16 15   0
Base
15   0
Limit
15   0
  • Base: 一个32位的值,包含段开始的线性地址。
  • Limit: 20位值告诉最大可寻址单元,以1字节为单位,或以4KiB页为单位。 因此,如果选择页面粒度并将 Limit 值设置为0xFFFFF,则该段将在32位模式下跨越整个4 GiB地址空间。

在64位模式下,忽略BaseLimit值,每个描述符覆盖整个线性地址空间,不管它们设置为什么。

有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的Section 3.4.5: Segment DescriptorsFigure 3-8: Segment Descriptor

Access Byte
7 6 5 4 3 2 1 0
P DPL S E DC RW A
  • P: Present位。 启用条目为引用向有效段。 必须为任何有效段设(1)。
  • DPL: 描述符特权级别字段。 包含段的 CPU特权级别 0 =最高权限(内核),3 = 最低权限(用户应用程序)。
  • S: 描述符类型位。 如果清 (0),则描述符定义一个系统段 (例如 任务状态段-Task State Segment)。 如果设(1),则定义代码或数据段。
  • E: Executable(可执行)位。 如果清(0),则描述符定义数据段。 如果设(1),它定义了一个可以用于执行的代码段。
  • DC: Direction位/Conforming位。
    • 对于数据(Data)选择器: Direction 位。 如果清(0),则该段将向上增长。 如果设(1)段向下增长,即Offset必须大于Limit
    • 对于代码(Code)选择器:Conforming 位。
      • 如果清(0)该段中的代码只能从Privl中设置的Ring执行。
      • 如果设(1),此段可以从相等或较低的特权级别执行代码。 例如,Ring3中的代码可以跳转到Ring2段中的conforming代码。 Privl字段表示允许执行该段的最高权限级别。 例如,Ring0中的代码不能far-jump到 Privl 为2的conforming代码段,而ring2和ring中的代码可以。 请注意,跳转后特权级别保持不变,即从Ring3到Privl为2的段的far-jump仍保留在Ring3中。
  • RW: 可读位/可写位。
    • 对于代码段:可读位。 如果清(0),则不允许对此段进行读取访问。 如果设(1),则允许读取访问。 永远不允许对代码段进行写访问。
    • 对于数据段:可写位。 如果清 (0),则不允许对此段进行写访问。 如果设(1),则允许写访问。 数据段始终允许读取访问。
  • A: Accessed(已访问)位。 最好清(0),CPU将在访问段时设它为1。
Flags
3 2 1 0
G DB L Reserved
  • G: 粒度(Granularity )标志,指示Limit值的缩放大小。 如果清 (0),则 Limit 以1字节块为单位 (字节粒度)。 如果设(1),Limit单位是4KiB块(页面粒度)。
  • DB: Size标志。 如果清(0),则描述符定义一个16位保护模式的段。 如果设 (1),它定义了一个32位受保护模式的段。 GDT可以同时具有16位和32位选择器。
  • L: 长模式代码标志。 如果设(1),则描述符定义64位代码段。 当它设1时,Sz 应始终清0。 对于任何其它类型的段(其它代码类型或任何数据段),它应该要清(0)。

系统段描述符(System Segment Descriptor)

对于系统段,例如定义 任务状态段(Task State Segment)本地描述符表(Local Descriptor Table) 的系统段, Access Byte的格式略有不同,以便定义不同类型的系统段,而不仅仅是代码段和数据段。

有关详细信息,请参阅《英特尔软件开发人员手册》,Section 3.5: System Descriptor TypesSection 3.5: System Descriptor Types

Access Byte
7 6 5 4 3 2 1 0
P    DPL S Type
  • Type: 系统段的类型。

32位保护模式下可用的类型:

  • 0x1: 16-bit TSS (Available)
  • 0x2: LDT
  • 0x3: 16-bit TSS (Busy)
  • 0x9: 32-bit TSS (Available)
  • 0xB: 32-bit TSS (Available)

长模式下可用的类型:

  • 0x2: LDT
  • 0x9: 64-bit TSS (Available)
  • 0xB: 64-bit TSS (Available)

长模式系统段描述符(Long Mode System Segment Descriptor)

对于长模式(Long Mode)中的Task State SegmentLocal Descriptor Table段描述符(Segment Descriptor)的格式不同,以确保 Base 值可以包含64位 线性地址。 它需要占用了两个一般条目表中的空间,且采用一种小端格式,因此该条目的下半部分在表中的上半部分之前。

有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的Section 7.2.3: TSS Descriptor in 64-bit ModeFigure 7-4: Format of TSS and LDT Descriptors in 64-bit Mode

64-bit System Segment Descriptor
127   96
Reserved
95   64
Base
63   32
63   56 55   52 51   48 47   40 39   32
Base
31   24
Flags
3   0
Limit
19   16
Access Byte
7   0
Base
23   16
31   16 15   0
Base
15   0
Limit
15   0

另见

文章

外部参考

de:Global Descriptor Table