“Global Descriptor Table”的版本间差异
(创建页面,内容为““全局描述符表”(“GDT”)是特定于 IA-32]和[[X86-64 | X86-64体系结构的二进制数据结构。它包含告诉CPU关于内存分段的条目。 类似的中断描述符表包含任务和中断描述符。 建议阅读GDT教程。 == GDTR == “GDT”由“GDTR”寄存器中的值指向。 这是使用“LGDT”汇编指令加载的,该指令的参数是指向“GDT描述符”…”) |
|||
第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|中断]] 描述符。 | |||
建议阅读[[GDT教程]]。 | 建议阅读[[GDT Tutorial|GDT教程]]。 | ||
== | == GDTR寄存器 == | ||
'''GDT'''由'''GDTR'''寄存器中的值指向。 这是使用'''LGDT'''汇编指令加载的,该指令的参数是指向'''GDT描述符'''结构的指针: | |||
{| class="wikitable" | {| class="wikitable" | ||
第15行: | 第15行: | ||
|'''Size'''<br><br>15 <span style="float: right;">0</span> | |'''Size'''<br><br>15 <span style="float: right;">0</span> | ||
|} | |} | ||
* '''Size:''' | * '''Size:''' 表的大小(以字节为单位)减去1。 之所以发生这种减法,是因为 '''size''' 的最大值是65535的,而'''GDT'''的长度最多可达65536个字节 (8192个条目)。 此外,'''gdt'''不可以具有0字节的大小。 | ||
* '''Offset:''' | * '''Offset:''' '''GDT'''的线性地址(不是物理地址,分页适用)。 | ||
请注意,'''LGDT'''加载的数据量在32位和64位模式中不同,偏移量在32位模式中为4字节长,在64位模式中为8字节长。 | |||
有关更多信息,请参阅《英特尔软件开发人员手册》 (第3-A卷) 的 '''Section 2.4.1: Global Descriptor Table Register (GDTR)''' 和 '''Figure 2-6: Memory Management Registers'''。 | |||
== | == 表说明 == | ||
'''GDT'''中的条目长度为8字节,形成如下表格: | |||
{|class="wikitable" | {|class="wikitable" | ||
|+ Global Descriptor Table | |+ Global Descriptor Table | ||
! | ! 地址 !! 内容 | ||
|- | |- | ||
| GDTR Offset + 0 || Null | | GDTR Offset + 0 || Null | ||
第41行: | 第41行: | ||
|} | |} | ||
'''GDT''' (条目0) 中的第一个条目应始终为null,并应使用后续条目。 | |||
表中的条目由'''[[Segment Selector|段选择器(Segment Selectors)]]'''访问,这些条目通过汇编指令或硬件功能(如'''[[Interrupts|中断]]''')加载到'''[[Segmentation|段]]'''寄存器中。 | |||
== | ==段描述符(Segment Descriptor)== | ||
表中的每个条目都有一个复杂的结构: | |||
{| class="wikitable" | {| class="wikitable" | ||
|+ Segment Descriptor | |+ Segment Descriptor | ||
第70行: | 第70行: | ||
* '''Base:''' 一个32位的值,包含段开始的线性地址。 | * '''Base:''' 一个32位的值,包含段开始的线性地址。 | ||
* '''Limit:''' | * '''Limit:''' 20位值告诉最大可寻址单元,以1字节为单位,或以4KiB页为单位。 因此,如果选择页面粒度并将 '''Limit''' 值设置为0xFFFFF,则该段将在32位模式下跨越整个4 GiB地址空间。 | ||
在64位模式下,忽略'''Base'''和'''Limit'''值,每个描述符覆盖整个线性地址空间,不管它们设置为什么。 | |||
有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的'''Section 3.4.5: Segment Descriptors'''和'''Figure 3-8: Segment Descriptor'''。 | |||
{| class="wikitable" | {| class="wikitable" | ||
第88行: | 第88行: | ||
!style="width: 12.5%;"|0 | !style="width: 12.5%;"|0 | ||
|- | |- | ||
|''' | |'''P''' ||colspan=2|'''DPL''' || '''S''' || '''E''' || '''DC''' || '''RW''' || '''A''' | ||
|} | |} | ||
* ''' | * '''P:''' 当前位。 允许条目引用有效段。 必须为任何有效段设('''1''')。 | ||
* ''' | * '''DPL:''' 描述符特权级别字段。 包含段的[[Security#Rings| CPU特权级别]] '''0''' =最高权限(内核),'''3''' = 最低权限(用户应用程序)。 | ||
* ''' | * '''S:''' 描述符类型位。 如果清 ('''0'''),则描述符定义一个系统段 (例如 [[Task_State_Segment|任务状态段-Task State Segment]])。 如果设('''1'''),则定义代码或数据段。 | ||
* ''' | * '''E:''' Executable bit. 如果清('''0'''),则描述符定义数据段。 如果设('''1'''),它定义了一个可以从中执行的代码段。 | ||
* '''DC:''' Direction bit/Conforming bit. | * '''DC:''' Direction bit/Conforming bit. | ||
** 对于数据选择器: Direction bit。 如果清('''0'''),则该段将向上增长。 如果设('''1''')段[[Expand_Down|向下增长]],即'''Offset'''必须大于'''Limit'''。 | |||
** 对于代码选择器:Conforming bit。 | |||
*** If Clear('''0''')该段中的代码只能从'''Privl'''中设置的Ring执行。 | |||
*** 如果设('''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'''),则允许写访问。 数据段始终允许读取访问。 | |||
* ''' | * '''A:''' Accessed bit. 最好清('''0'''),CPU将在访问段时设它为1。 | ||
{| class="wikitable" | {| class="wikitable" | ||
第113行: | 第113行: | ||
!style="width: 25%;"|0 | !style="width: 25%;"|0 | ||
|- | |- | ||
|''' | |'''G''' || '''DB''' || '''L''' | ||
|Reserved | |Reserved | ||
|} | |} | ||
* ''' | * '''G:''' 粒度(Granularity )标志,指示'''Limit'''值的缩放大小。 如果清 ('''0'''),则 '''Limit''' 以1字节块为单位 (字节粒度)。 如果设('''1'''),'''Limit'''单位是4KiB块(页面粒度)。 | ||
* ''' | * '''DB:''' Size flag. 如果清('''0'''),则描述符定义一个16位保护模式段。 如果设 ('''1'''),它定义了一个32位受保护的模式段。 GDT可以同时具有16位和32位选择器。 | ||
* ''' | * '''L:''' Long-mode code flag. 如果设('''1'''),则描述符定义64位代码段。 设1时,'''Sz''' 应始终清0。 对于任何其他类型的段(其他代码类型或任何数据段),它应该是清('''0''')。 | ||
==系统段描述符== | |||
对于系统段,例如定义 '''[[Task State Segment|任务状态段]]''' 或 '''[[Local Descriptor Table|本地描述符表]]''' 的系统段, '''Access Byte'''的格式略有不同,以便定义不同类型的系统段,而不是代码段和数据段。 | |||
有关详细信息,请参阅《英特尔软件开发人员手册》,'''Section 3.5: System Descriptor Types'''和'''Section 3.5: System Descriptor Types'''。 | |||
{| class="wikitable" | |||
|+ Access Byte | |||
|- | |||
!style="width: 12.5%;"|7 | |||
!style="width: 12.5%;"|6 | |||
!style="width: 12.5%;"|5 | |||
!style="width: 12.5%;"|4 | |||
!style="width: 12.5%;"|3 | |||
!style="width: 12.5%;"|2 | |||
!style="width: 12.5%;"|1 | |||
!style="width: 12.5%;"|0 | |||
|- | |||
|'''P''' ||colspan=2|'''DPL''' || '''S''' || colspan=4|'''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]]'''中的'''[[Task State Segment]]'''或'''[[Local Descriptor Table]]'''。 '''Segment Descriptor'''的格式不同,以确保 '''Base''' 值可以包含64位 '''[[Linear Address|线性地址]]'''。 它占用了两个常用条目表中的空间,采用了一种小端格式,因此该条目的下半部分在表中的上半部分之前。 | |||
有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的'''Section 7.2.3: TSS Descriptor in 64-bit Mode'''和'''Figure 7-4: Format of TSS and LDT Descriptors in 64-bit Mode'''。 | |||
{| class="wikitable" style="display: inline-table;" | |||
|+ 64-bit System Segment Descriptor | |||
|- | |||
!colspan=5 style="text-align: left;"|127 <span style="float: right;">96</span> | |||
|- | |||
|colspan=5|Reserved | |||
|- | |||
!colspan=5 style="text-align: left;"|95 <span style="float: right;">64</span> | |||
|- | |||
|colspan=5|'''Base'''<br>63 <span style="float: right;">32</span> | |||
|- | |||
!style="width: 20%; text-align: left;"|63 <span style="float: right;">56</span> | |||
!style="width: 12.5%; text-align: left;"|55 <span style="float: right;">52</span> | |||
!style="width: 12.5%; text-align: left;"|51 <span style="float: right;">48</span> | |||
!style="width: 25%; text-align: left;"|47 <span style="float: right;">40</span> | |||
!style="width: 25%; text-align: left;"|39 <span style="float: right;">32</span> | |||
|- | |||
|'''Base'''<br>31 <span style="float: right;">24</span> | |||
|'''Flags'''<br>3 <span style="float: right;">0</span> | |||
|'''Limit'''<br>19 <span style="float: right;">16</span> | |||
|'''Access Byte'''<br>7 <span style="float: right;">0</span> | |||
|'''Base'''<br>23 <span style="float: right;">16</span> | |||
|- | |||
!colspan=3 style="text-align: left;"|31 <span style="float: right;">16</span> | |||
!colspan=2 style="text-align: left;"|15 <span style="float: right;">0</span> | |||
|- | |||
|colspan=3|'''Base'''<br>15 <span style="float: right;">0</span> | |||
|colspan=2|'''Limit'''<br>15 <span style="float: right;">0</span> | |||
|} | |||
== 另见 == | == 另见 == | ||
=== 文章 === | ===文章=== | ||
* [[GDT Tutorial]] | * [[GDT Tutorial|GDT教程]] | ||
* [[Getting to 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 | ||
=== 外部参照 === | ===外部参照=== | ||
* [http://files.osdev.org/mirrors/geezer/os/pm.htm Protected Mode tutorial] | * [http://files.osdev.org/mirrors/geezer/os/pm.htm Protected Mode tutorial] | ||
* [http://www.intel.com/design/processor/manuals/253668.pdf Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A:. System Programming Guide, Part 1 (order number 253668)] chapter 2.4[[Category:X86 CPU]] | * [http://www.intel.com/design/processor/manuals/253668.pdf Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A:. System Programming Guide, Part 1 (order number 253668)] chapter 2.4[[Category:X86 CPU]] | ||
[[de:Global Descriptor Table]] |
2022年3月6日 (日) 14:13的版本
全局描述符表(Global Descriptor Table - GDT)是特定于IA-32和x86-64体系结构的二进制数据结构。 它包含告诉CPU有关内存分段的条目。 还存在一个类似的 中断描述符表(Interrupt Descriptor Table),其中包含 任务 和 中断 描述符。
建议阅读GDT教程。
GDTR寄存器
GDT由GDTR寄存器中的值指向。 这是使用LGDT汇编指令加载的,该指令的参数是指向GDT描述符结构的指针:
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位模式中不同,偏移量在32位模式中为4字节长,在64位模式中为8字节长。
有关更多信息,请参阅《英特尔软件开发人员手册》 (第3-A卷) 的 Section 2.4.1: Global Descriptor Table Register (GDTR) 和 Figure 2-6: Memory Management Registers。
表说明
GDT中的条目长度为8字节,形成如下表格:
地址 | 内容 |
---|---|
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)
表中的每个条目都有一个复杂的结构:
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位模式下,忽略Base和Limit值,每个描述符覆盖整个线性地址空间,不管它们设置为什么。
有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的Section 3.4.5: Segment Descriptors和Figure 3-8: Segment Descriptor。
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
P | DPL | S | E | DC | RW | A |
- P: 当前位。 允许条目引用有效段。 必须为任何有效段设(1)。
- DPL: 描述符特权级别字段。 包含段的 CPU特权级别 0 =最高权限(内核),3 = 最低权限(用户应用程序)。
- S: 描述符类型位。 如果清 (0),则描述符定义一个系统段 (例如 任务状态段-Task State Segment)。 如果设(1),则定义代码或数据段。
- E: Executable bit. 如果清(0),则描述符定义数据段。 如果设(1),它定义了一个可以从中执行的代码段。
- DC: Direction bit/Conforming bit.
- 对于数据选择器: Direction bit。 如果清(0),则该段将向上增长。 如果设(1)段向下增长,即Offset必须大于Limit。
- 对于代码选择器:Conforming bit。
- If Clear(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 bit. 最好清(0),CPU将在访问段时设它为1。
3 | 2 | 1 | 0 |
---|---|---|---|
G | DB | L | Reserved |
- G: 粒度(Granularity )标志,指示Limit值的缩放大小。 如果清 (0),则 Limit 以1字节块为单位 (字节粒度)。 如果设(1),Limit单位是4KiB块(页面粒度)。
- DB: Size flag. 如果清(0),则描述符定义一个16位保护模式段。 如果设 (1),它定义了一个32位受保护的模式段。 GDT可以同时具有16位和32位选择器。
- L: Long-mode code flag. 如果设(1),则描述符定义64位代码段。 设1时,Sz 应始终清0。 对于任何其他类型的段(其他代码类型或任何数据段),它应该是清(0)。
系统段描述符
对于系统段,例如定义 任务状态段 或 本地描述符表 的系统段, Access Byte的格式略有不同,以便定义不同类型的系统段,而不是代码段和数据段。
有关详细信息,请参阅《英特尔软件开发人员手册》,Section 3.5: System Descriptor Types和Section 3.5: System Descriptor Types。
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中的Task State Segment或Local Descriptor Table。 Segment Descriptor的格式不同,以确保 Base 值可以包含64位 线性地址。 它占用了两个常用条目表中的空间,采用了一种小端格式,因此该条目的下半部分在表中的上半部分之前。
有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的Section 7.2.3: TSS Descriptor in 64-bit Mode和Figure 7-4: Format of TSS and LDT Descriptors in 64-bit Mode。
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 |
另见
文章
- GDT教程
- 到达Ring 3
- 段
- http://www.osdever.net/tutorials/view/the-world-of-protected-mode - how to set up GDT in assembler