查看“Interrupt Descriptor Table”的源代码
←
Interrupt Descriptor Table
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
'''中断描述符表'''('''IDT-Interrupt Descriptor Table''')是特定于[[IA32_Architecture_Family|IA-32]]和[[X86-64|x86-64]]体系结构的二进制数据结构。 它是[[Real Mode|实模式]]里中断向量表([[IVT]])的[[Protected Mode|保护模式]]和长模式对应物,用以告诉CPU[[Interrupt Service Routines|中断服务例程]] (ISR-Interrupt Service Routines) 所在的位置 (一个中断向量代表一个例程)。 它在结构上类似于[[Global Descriptor Table|全局描述符表-GDT]]。 IDT条目被称为门(gate)。 它可以包含中断门、任务门和陷阱门。 在实现IDT之前,请确保你有一个有效的GDT。 == IDTR == '''IDT'''的位置保存在'''IDTR'''('''IDT Register'''寄存器)中。 这是使用'''LIDT'''汇编指令加载的,该指令的参数为'''IDTR''': {| class="wikitable" |+IDT Descriptor (IDTR): !style="width: 66%; text-align: left;" |79 (64-bit Mode)<br>48 (32-bit Mode) <span style="float: right;">16</span> !style="width: 34%; text-align: left; vertical-align: bottom;" |15 <span style="float: right;">0</span> |- |'''Offset'''<br>63 (64-bit Mode)<br>31 (32-bit Mode) <span style="float: right;">0</span> |'''Size'''<br><br>15 <span style="float: right;">0</span> |} * '''Size''': 比“IDT”的大小(字节)小一。 * '''Offset''': '''Interrupt Descriptor Table(中断描述符表)'''的线性地址(不是物理地址,应用分页)。 请注意,'''LIDT'''加载的数据量在32位和64位模式下有所不同,'''Offset'''在32位模式下为4字节长,在64位模式下为8字节长。 这与'''[[GDT]]'''类似,只是: * 第一个条目(偏移量为零)可用于'''IDT'''。(译者注:GDT的第一个条目为空无用条目) * 有256个中断向量 (0..255),因此 '''IDT'''应该具有256个条目,每个条目对应于特定的中断向量。 * 虽然'''IDT'''可以包含256个以上的条目,但它们会被忽略。 * 虽然'''IDT'''可以包含少于256个条目,但任何不存在的条目(由于此或其他原因)将在尝试访问它们时生成一个'''[[Exceptions#General Protection Fault|一般保护异常(General Protection Fault)]]'''。 理想情况下,'''IDT''' 应该包含足够的条目,以便可以处理此故障 (它本身是一个中断向量)。 有关更多信息,请参阅《英特尔软件开发人员手册》第3-A卷的'''Section 2.4.3: IDTR Interrupt Descriptor Table Register'''和'''Figure 2-6: Memory Management Registers'''。 ==IA-32上的结构== === 表 Table === 在32位处理器上,'''IDT''' 中的条目长度为8个字节,并形成如下表: {|class="wikitable" |+Interrupt Descriptor Table (32-bit) ! 地址 !! 内容 |- | IDTR Offset + 0 || Entry 0 |- | IDTR Offset + 8 || Entry 1 |- | IDTR Offset + 16 || Entry 2 |- style="text-align: center;" | '''...''' || '''...''' |- | IDTR Offset + 2040 || Entry 255 |} 给定'''中断向量'''的对应项在内存中被指向,方法是将向量缩放8,并将其添加到'''IDTR'''的'''Offset'''字段中的值。 === 门描述符(Gate Descriptor) === 表中的每个条目都有一个复杂的结构: {| class="wikitable" |+Gate Descriptor (32-bit): !style="width: 50%; text-align: left;"|63 <span style="float: right;">48</span> !style="width: 3.125%"|47 !style="width: 6.25%; text-align: left;"|46 <span style="float: right;">45</span> !style="width: 3.125%"|44 !style="width: 12.5%; text-align: left;"|43 <span style="float: right;">40</span> !style="width: 25%; text-align: left;"|39 <span style="float: right;">32</span> |- |'''Offset'''<br>31 <span style="float: right;">16</span> |style="text-align: center; vertical-align: top;"|'''P''' |'''DPL'''<br>1 <span style="float: right;">0</span> |style="text-align: center; vertical-align: top;"|0 |'''Gate Type'''<br>3 <span style="float: right;">0</span> |style="vertical-align:top"|Reserved |- !style="text-align: left;" |31 <span style="float: right;">16</span> !style="text-align: left;" colspan="5" |15 <span style="float: right;">0</span> |- |'''Segment Selector'''<br>15 <span style="float: right;">0</span> |colspan="5" |'''Offset'''<br>15 <span style="float: right;">0</span> |} * '''Offset:'''一个32位的值,分为两部分。它表示'''[[Interrupt Service Routines|中断服务例程]]'''入口点的地址。 * '''Selector:''' '''[[Segment Selector|段选择器]]'''具有多个字段,这些字段必须指向'''[[GDT]]'''中的有效代码段。 * '''Gate Type:''' 一个4位值,它定义了此'''中断描述符'''的门类型。有五个有效的类型值: ** '''0b0101''' or '''0x5''': 任务门(Task Gate),请注意,在这种情况下,'''Offset''' 值未使用,应设置为零。 ** '''0b0110''' or '''0x6''': 16位中断门 ** '''0b0111''' or '''0x7''': 16位陷阱门 ** '''0b1110''' or '''0xE''': 32位中断门 ** '''0b1111''' or '''0xF''': 32位陷阱门 * '''DPL:''' 一个2位值,用于定义'''[[Security#Rings|CPU特权级别]]''',允许通过'''INT'''指令访问此中断。 硬件中断会忽略此机制。 * '''P:''' Present位。必须设置('''1''')才能使描述符有效。 有关更多信息,请参阅《英特尔软件开发人员手册》 (第3-A卷) 的 '''Section 6.11: IDT Descriptors''' 和 '''Figure 6-2: IDT Gate Descriptors'''。 === 示例代码 === C结构体: <source lang="c"> struct InterruptDescriptor32 { uint16_t offset_1; // offset bits 0..15 uint16_t selector; // a code segment selector in GDT or LDT uint8_t zero; // unused, set to 0 uint8_t type_attributes; // gate type, dpl, and p fields uint16_t offset_2; // offset bits 16..31 }; </source> 人们可能会使用的示例 ''type_attributes'' 值(假设DPL为0): * 32-bit '''Interrupt Gate: 0x8E''' (p=1, dpl=0b00, type=0b1110 => type_attributes=0b1000_1110='''0x8E''') * 32-bit '''Trap Gate: 0x8F''' (p=1, dpl=0b00, type=0b1111 => type_attributes=1000_1111b='''0x8F''') * '''Task Gate: 0x85''' (p=1, dpl=0b00, type=0b0101 => type_attributes=0b1000_0101='''0x85''') ==x86-64上的结构== === 表 Table=== 在64位处理器上,'''IDT'''中的条目为16字节长,形成如下表格: {|class="wikitable" |+Interrupt Descriptor Table (64-bit) ! Address !! Content |- | IDTR Offset + 0 || Entry 0 |- | IDTR Offset + 16 || Entry 1 |- | IDTR Offset + 32 || Entry 2 |- style="text-align: center;" | '''...''' || '''...''' |- | IDTR Offset + 4080 || Entry 255 |} 通过将给定的'''中断向量'''缩放16,并将其添加到'''IDTR'''的'''Offset'''字段中的值,可以在内存中指向该'''中断向量'''的相应条目。 === 门描述符(Gate Descriptor)=== 表中的每个条目都有一个复杂的结构: {| class="wikitable" |+Gate Descriptor (64-bit): !colspan="7" style="text-align: left;"|127 <span style="float: right;">96</span> |- |colspan="7" |Reserved |- !colspan="7" style="text-align: left;"|95 <span style="float: right;">64</span> |- |colspan="7" |'''Offset'''<br>63 <span style="float: right;">32</span> |- !style="width: 50%; text-align: left;"|63 <span style="float: right;">48</span> !style="width: 3.125%"|47 !style="width: 6.25%; text-align: left;"|46 <span style="float: right;">45</span> !style="width: 3.125%"|44 !style="width: 12.5%; text-align: left;"|43 <span style="float: right;">40</span> !style="width: 15.625%; text-align: left;"|39 <span style="float: right;">35</span> !style="width: 9.375%; text-align: left;"|34 <span style="float: right;">32</span> |- |'''Offset'''<br>31 <span style="float: right;">16</span> |style="text-align: center; vertical-align: top;"|'''P''' |'''DPL'''<br>1 <span style="float: right;">0</span> |style="text-align: center; vertical-align: top;"|0 |'''Gate Type'''<br>3 <span style="float: right;">0</span> |style="vertical-align:top"|Reserved |'''IST'''<br>2 <span style="float: right;">0</span> |- !style="text-align: left;" |31 <span style="float: right;">16</span> !style="text-align: left;" colspan="6" |15 <span style="float: right;">0</span> |- |'''Segment Selector'''<br>15 <span style="float: right;">0</span> |colspan="6" |'''Offset'''<br>15 <span style="float: right;">0</span> |} * '''Offset:'''一个64位的值,分为三部分。 它表示'''[[Interrupt Service Routines|中断服务例程]]'''入口点的地址。 * '''Selector:''' 一个 '''[[Segment Selector|段选择器]]''',具有多个字段,这些字段必须指向你的 '''[[GDT]]''' 中的有效代码段。 * '''IST:''' 一个3位值,它是'''Interrupt Stack Table'''的偏移量,存储在'''[[Task State Segment]]'''中。 如果所有位都设置为零,则不使用'''Interrupt Stack Table'''。 * '''Gate Type:''' 一个4位值,它定义了此 '''Interrupt Descriptor''' 代表的门的类型。 在长模式下,有两个有效的类型值: ** '''0b1110'''或 '''0xE''':64位中断门 ** '''0b1111''' 或 '''0xF''': 64位陷阱门 * '''DPL:''' 2位值,定义允许通过'''INT'''指令访问此中断的'''[[Security#Rings|CPU特权级别]]'''。 硬件中断忽略了这种机制。 * '''P:''' Present 位 必须设置 ('''1'''),描述符才有效。 在你的'''[[Interrupt Service Routines|中断服务例程]]'''中,请记住使用'''IRETQ'''指令而不是'''IRET'''指令从中断返回,因为汇编器不会为你转换该指令。 论坛上许多与64位IDT相关的问题都是由缺少 'Q' 引起的。 别让这种事发生在你身上。 有关详细信息,请参阅《英特尔软件开发人员手册》第3-A卷的'''Section 6.14.1: 64-Bit Mode IDT'''和'''Figure 6-8: 64-Bit IDT Gate Descriptors'''。 === 示例代码 === C结构体: <source lang="c"> struct InterruptDescriptor64 { uint16_t offset_1; // offset bits 0..15 uint16_t selector; // a code segment selector in GDT or LDT uint8_t ist; // bits 0..2 holds Interrupt Stack Table offset, rest of bits zero. uint8_t type_attributes; // gate type, dpl, and p fields uint16_t offset_2; // offset bits 16..31 uint32_t offset_3; // offset bits 32..63 uint32_t zero; // reserved }; </source> 人们可能会使用的示例 ''type_tributes''值(假设DPL为0): * 64-bit '''Interrupt Gate: 0x8E''' (p=1, dpl=0b00, type=0b1110 => type_attributes=0b1000_1110='''0x8E''') * 64-bit '''Trap Gate: 0x8F''' (p=1, dpl=0b00, type=0b1111 => type_attributes=1000_1111b='''0x8F''') == 门类型 == 基本上有两种中断: 当代码执行由于错误代码而遇到'''[[Exception|Exception]]'''时发生的事件,或者处理与当前正在执行的代码无关的事件时发生的事件。 在第一种情况下,有必要保存'''当前'''执行指令的地址,以便可以重试,这些称为 “陷阱(Traps)”。 在第二种情况下,保存''下一条''指令的地址是必要的,这样就可以在中断的地方继续执行。 这可能是由IRQ或其他硬件事件或使用'''INT'''指令引起的。 需要注意的另一个区别是,使用'''Traps'''时,在服务例程期间可能会发生新的中断, 但当CPU为IRQ提供服务时,进一步的中断会被屏蔽,直到发出“中断结束(End of Interrupt)”信号。 如何处理某个中断取决于你在IDT条目中放置的门的类型。 === 中断门(Interrupt Gate) === '''中断门'''用于指定一个'''[[Interrupt Service Routines|中断服务例程]]'''。 例如,当在保护模式下运行时执行汇编指令'''INT 50'''时,CPU将查找'''IDT'''中的第50个条目(位于50*8)。 然后加载中断门的 '''选择器(Selector)'''; 和 '''偏移(Offset)'''值。 '''选择器(Selector)'''和'''偏移量(Offset)'''用于调用'''中断服务例程'''。 当执行'''IRET'''指令时,CPU从中断返回。 如果CPU以32位模式运行,并且指定的选择器是16位门,则在调用'''ISR'''后,CPU将进入16位'''受保护模式'''。 在这种情况下,要返回,应该使用'''O32 IRET'''指令,否则CPU将不知道它应该执行32位返回(从[[stack|堆栈]]读取32位值,而不是16位)。 === 陷阱门(Trap Gate) === '''陷阱门'''应该用来处理'''[[Exceptions|异常]]'''。 当一个异常发生时,有时会在堆栈上放置一个错误代码,应该在中断返回之前弹出该代码。 '''陷阱门'''和'''中断门'''是相似的,它们的描述符在结构上是相同的,只是在'''门类型'''字段中有所不同。 不同之处在于,对于 '''中断门''',中断在进入时会自动禁用,并在 '''IRET''' 时重新启用,而对于 '''陷阱门''' 则不会发生。 === 任务门(Task Gate) === '''任务门'''是特定于IA-32的门类型,用于硬件任务切换。 对于'''任务门''','''选择器'''值应指向'''[[GDT]]'''中的位置,该位置指定 '''[[Task State Segment|任务状态段]]''',而不是代码段, '''偏移量'''值未使用,应设置为零。 当CPU处理该中断时,它将执行到指定任务的硬件任务切换,而不是跳转到服务例程。 返回被中断的任务的指针将存储在'''TSS''' 的'''Task Link(任务链接)'''字段中。 {{Quotation|"*注释* 因为IA-32任务不是可重入(re-entrant)的,所以中断处理程序任务必须在其完成处理中断时和执行IRET指令之间禁用中断。 此操作可防止在中断任务的TSS仍被标记为忙时发生另一个中断,这将导致常规保护 (#GP-general-protection) 异常。"|英特尔软件开发人员手册}} 这种类型的门不经常使用,因为硬件任务切换很慢,并且在现代处理器上几乎没有优化。 同样,它在 [[X86-64|x86-64]]上已被完全删除。 ==另见== === 文章 === * [[GDT]] * [[IDT_problems|IDT problems]] === 外部链接 === * [http://www.logix.cz/michal/doc/i386/chp09-00.htm Michal Ludvig's Intel 80386 Programmer's Reference Manual chapter 9] [[Category:X86 CPU]] [[Category:Interrupts]] [[de:Interrupt_Descriptor_Table]]
本页使用的模板:
模板:If
(
查看源代码
)
模板:Quotation
(
查看源代码
)
模板:Show1
(
查看源代码
)
返回至“
Interrupt Descriptor Table
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
变体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息