“Global Descriptor Table”的版本间差异
第18行: | 第18行: | ||
* '''Offset:''' '''GDT'''的线性地址(不是物理地址,分页适用)。 | * '''Offset:''' '''GDT'''的线性地址(不是物理地址,分页适用)。 | ||
请注意,'''LGDT''' | 请注意,'''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'''。 | 有关更多信息,请参阅《英特尔软件开发人员手册》 (第3-A卷) 的 '''Section 2.4.1: Global Descriptor Table Register (GDTR)''' 和 '''Figure 2-6: Memory Management Registers'''。 | ||
第41行: | 第41行: | ||
|} | |} | ||
'''GDT''' (条目0) | '''GDT''' (条目0) 中的第一个条目应始终为null,只使用后续条目。 | ||
表中的条目由'''[[Segment Selector|段选择器(Segment Selectors)]]'''访问,这些条目通过汇编指令或硬件功能(如'''[[Interrupts|中断]]''')加载到'''[[Segmentation|段]]'''寄存器中。 | 表中的条目由'''[[Segment Selector|段选择器(Segment Selectors)]]'''访问,这些条目通过汇编指令或硬件功能(如'''[[Interrupts|中断]]''')加载到'''[[Segmentation|段]]'''寄存器中。 | ||
第47行: | 第47行: | ||
==段描述符(Segment Descriptor)== | ==段描述符(Segment Descriptor)== | ||
上面表中的每个条目(Entry)都有一个复杂的结构: | |||
{| class="wikitable" | {| class="wikitable" | ||
|+ Segment Descriptor | |+ Segment Descriptor | ||
第91行: | 第91行: | ||
|} | |} | ||
* '''P:''' | * '''P:''' Present位。 启用条目为引用向有效段。 必须为任何有效段设('''1''')。 | ||
* '''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:''' | * '''E:''' Executable(可执行)位。 如果清('''0'''),则描述符定义数据段。 如果设('''1'''),它定义了一个可以用于执行的代码段。 | ||
* '''DC:''' Direction bit/Conforming | * '''DC:''' Direction bit/Conforming 位。 | ||
** | ** 对于数据(Data)选择器: Direction 位。 如果清('''0'''),则该段将向上增长。 如果设('''1''')段[[Expand_Down|向下增长]],即'''Offset'''必须大于'''Limit'''。 | ||
** | ** 对于代码(Code)选择器:Conforming 位。 | ||
*** | *** 如果清('''0''')该段中的代码只能从'''Privl'''中设置的Ring执行。 | ||
*** 如果设('''1'''),此段可以从相等或较低的特权级别执行代码。 例如,Ring3中的代码可以跳转到Ring2段中的''conforming''代码。 '''Privl'''字段表示允许执行该段的最高权限级别。 例如,Ring0中的代码不能far-jump到 '''Privl''' 为2的conforming代码段,而ring2和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'''),则允许读取访问。 永远不允许对代码段进行写访问。 | ||
** 对于数据段:可写位。 如果清 ('''0'''),则不允许对此段进行写访问。 如果设('''1'''),则允许写访问。 数据段始终允许读取访问。 | ** 对于数据段:可写位。 如果清 ('''0'''),则不允许对此段进行写访问。 如果设('''1'''),则允许写访问。 数据段始终允许读取访问。 | ||
* '''A:''' | * '''A:''' Accessed(已访问)位。 最好清('''0'''),CPU将在访问段时设它为1。 | ||
{| class="wikitable" | {| class="wikitable" | ||
第118行: | 第118行: | ||
* '''G:''' 粒度(Granularity )标志,指示'''Limit'''值的缩放大小。 如果清 ('''0'''),则 '''Limit''' 以1字节块为单位 (字节粒度)。 如果设('''1'''),'''Limit'''单位是4KiB块(页面粒度)。 | * '''G:''' 粒度(Granularity )标志,指示'''Limit'''值的缩放大小。 如果清 ('''0'''),则 '''Limit''' 以1字节块为单位 (字节粒度)。 如果设('''1'''),'''Limit'''单位是4KiB块(页面粒度)。 | ||
* '''DB:''' | * '''DB:''' Size标志。 如果清('''0'''),则描述符定义一个16位保护模式的段。 如果设 ('''1'''),它定义了一个32位受保护模式的段。 GDT可以同时具有16位和32位选择器。 | ||
* '''L:''' | * '''L:''' 长模式代码标志。 如果设('''1'''),则描述符定义64位代码段。 当它设1时,'''Sz''' 应始终清0。 对于任何其他类型的段(其他代码类型或任何数据段),它应该要清('''0''')。 | ||
== | ==系统段描述符(System Segment Descriptor)== | ||
对于系统段,例如定义 '''[[Task State Segment| | 对于系统段,例如定义 '''[[Task State Segment|任务状态段(Task State Segment)]]''' 或 '''[[Local Descriptor Table|本地描述符表(Local Descriptor Table)]]''' 的系统段, '''Access Byte'''的格式略有不同,以便定义不同类型的系统段,而不仅仅是代码段和数据段。 | ||
有关详细信息,请参阅《英特尔软件开发人员手册》,'''Section 3.5: System Descriptor Types'''和'''Section 3.5: System Descriptor Types'''。 | 有关详细信息,请参阅《英特尔软件开发人员手册》,'''Section 3.5: System Descriptor Types'''和'''Section 3.5: System Descriptor Types'''。 | ||
第156行: | 第156行: | ||
* '''0xB:''' 64-bit TSS (Available) | * '''0xB:''' 64-bit TSS (Available) | ||
== | ==长模式系统段描述符(Long Mode System Segment Descriptor)== | ||
对于'''[[Long Mode]]'''中的'''[[Task State Segment]]'''或'''[[Local Descriptor Table]]'''。 ''' | 对于'''[[Long Mode|长模式(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'''。 | 有关详细信息,请参阅《英特尔软件开发人员手册》,第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'''。 | ||
第199行: | 第199行: | ||
* 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]] | [[de:Global Descriptor Table]] |
2022年3月7日 (一) 02:07的版本
全局描述符表(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位模式中不同,offset在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)
上面表中的每个条目(Entry)都有一个复杂的结构:
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: Present位。 启用条目为引用向有效段。 必须为任何有效段设(1)。
- DPL: 描述符特权级别字段。 包含段的 CPU特权级别 0 =最高权限(内核),3 = 最低权限(用户应用程序)。
- S: 描述符类型位。 如果清 (0),则描述符定义一个系统段 (例如 任务状态段-Task State Segment)。 如果设(1),则定义代码或数据段。
- E: Executable(可执行)位。 如果清(0),则描述符定义数据段。 如果设(1),它定义了一个可以用于执行的代码段。
- DC: Direction bit/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。
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 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 System Segment Descriptor)
对于长模式(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