Global Descriptor Table

来自osdev
跳到导航 跳到搜索

全局描述符表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