Interrupt Descriptor Table: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
(I felt this article could use somewhat of a rewrite as I found its formatting confusing and information kind of garbled (particularly information pertaining to 64-bit mode). Feel free to change formatting or wholly revert the edit if not welcome.)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(21 intermediate revisions by 7 users not shown)
Line 7:
== IDTR ==
 
The location of the '''IDT''' is kept in the '''IDTR''' ('''IDT''' register). This is loaded using the '''LGDTLIDT''' assembly instruction, whose argument is a pointer to an '''IDT Descriptor''' structure:
 
{| class="wikitable"
<pre>
|+IDT DESCRIPTORDescriptor (IDTR):
!style="width: 66%; text-align: left;" |79 (64-bit Mode)<br>48 (32-bit Mode)&nbsp;&nbsp;&nbsp;<span style="float: right;">16</span>
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
!style="width: 34%; text-align: left; vertical-align: bottom;" |15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
┃79 (64-bit Mode) / 48 (32-bit Mode) 16│15 0┃
|-
┠───────────────────────────────────────────────────────────────┼───────────────────────────────┨
|'''Offset'''<br>63 (64-bit Mode)<br>31 (32-bit Mode)&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
┃Offset │Size ┃
|'''Size'''<br><br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
┃63 (64-bit Mode) / 31 (32-bit Mode) 0│15 0┃
|}
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
</pre>
 
* '''Size''': One less than the size of the '''IDT''' in bytes.
* '''Offset''': The linear address of the '''Interrupt Descriptor Table''' (not the physical address, paging applies).
 
Note that the amount of data loaded by '''LGDTLIDT''' differs in 32-bit and 64-bit modes, '''Offset''' is 4 bytes long in 32-bit mode and 8 bytes long in 64-bit mode.
 
This is similar to the '''[[GDT]]''', except:
Line 38 ⟶ 37:
On 32-bit processors, the entries in the '''IDT''' are 8 bytes long and form a table like this:
 
{|class="wikitable"
<pre>
|+Interrupt Descriptor Table (32-bit)
Table: Address:
! Address !! Content
┏━━━━━━━━━━━┓
|-
┃ Entry 0 ┃ IDTR Offset + 0
| IDTR Offset + 0 || Entry 0
┠───────────┨
|-
┃ Entry 1 ┃ IDTR Offset + 8
| IDTR Offset + 8 || Entry 1
┠───────────┨
|-
┃ Entry 2 ┃ IDTR Offset + 16
| IDTR Offset + 16 || Entry 2
┠───────────┨
|- style="text-align: center;"
┃ ... ┃ ...
| '''...''' || '''...'''
┠───────────┨
|-
┃ Entry 255 ┃ IDTR Offset + 2040
| IDTR Offset + 2040 || Entry 255
┗━━━━━━━━━━━┛
|}
</pre>
 
The corresponding entry for a given '''Interrupt Vector''' is pointed to in memory by scaling the vector by 8 and adding it to the value in the '''Offset''' field of the '''IDTR'''.
 
=== EntriesGate Descriptor ===
 
Each entry in the table has a complex structure:
 
{| class="wikitable"
<pre>
|+Gate Descriptor (32-bit):
32-BIT INTERRUPT DESCRIPTOR
!style="width: 50%; text-align: left;"|63&nbsp;&nbsp;&nbsp;<span style="float: right;">48</span>
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━┯━━━━━┯━━┯━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━┓
!style="width: 3.125%"|47
┃63 48│47│46 45│44│43 40│39 32┃
!style="width: 6.25%; text-align: left;"|46&nbsp;&nbsp;&nbsp;<span style="float: right;">45</span>
┠───────────────────────────────────────────────┼──┼─────┼──┼───────────┼───────────────────────┨
!style="width: 3.125%"|44
┃Offset │P │DPL │0 │Gate Type │Reserved ┃
!style="width: 12.5%; text-align: left;"|43&nbsp;&nbsp;&nbsp;<span style="float: right;">40</span>
┃31 16│ │1 0│ │3 0│ 0┃
!style="width: 25%; text-align: left;"|39&nbsp;&nbsp;&nbsp;<span style="float: right;">32</span>
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━┷━━━━━┷━━┷━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━┛
|-
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|'''Offset'''<br>31&nbsp;&nbsp;&nbsp;<span style="float: right;">16</span>
┃31 16│15 0┃
|style="text-align: center; vertical-align: top;"|'''P'''
┠───────────────────────────────────────────────┼───────────────────────────────────────────────┨
|'''DPL'''<br>1&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
┃Segment Selector │Offset ┃
|style="text-align: center; vertical-align: top;"|0
┃15 0│15 0┃
|'''Gate Type'''<br>3&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|style="vertical-align:top"|Reserved
</pre>
|-
!style="text-align: left;" |31&nbsp;&nbsp;&nbsp;<span style="float: right;">16</span>
!style="text-align: left;" colspan="5" |15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|-
|'''Segment Selector'''<br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|colspan="5" |'''Offset'''<br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|}
 
* '''Offset:''' A 32-bit value, split in two parts. It represents the address of the entry point of the '''[[Interrupt Service Routines|Interrupt Service Routine]]'''.
* '''Selector:''' A 16-bit'''[[Segment valueSelector]]''' with multiple fields which must point to a valid code segment in your '''[[GDT]]'''. For more information, see '''Section 3.4.2: Segment Selectors''' and '''Figure 3-6: Segment Selector''' of the Intel Software Developer Manual, Volume 3-A.
* '''Gate Type:''' A 4-bit value which defines the type of gate this '''Interrupt Descriptor''' represents. There are five valid type values:
** '''0b0101''' or '''0x5''': Task Gate, note that in this case, the '''Offset''' value is unused and should be set to zero.
Line 86 ⟶ 92:
* '''P:''' Present bit. Must be set ('''1''') for the descriptor to be valid.
 
For more information, see '''Section 6.11: IDT Descriptors''' and '''Figure 6-2: IDT Gate Descriptors''' of the [https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.html Intel Software Developer Manual, Volume 3-A].
 
=== Example Code ===
Line 92 ⟶ 98:
C Struct:
 
<sourcesyntaxhighlight lang="c">
struct InterruptDescriptor32 {
uint16_t offset_1; // offset bits 0..15
Line 100 ⟶ 106:
uint16_t offset_2; // offset bits 16..31
};
</syntaxhighlight>
</source>
 
Example ''type_attributes'' values that people are likely to use (assuming DPL is 0):
Line 113 ⟶ 119:
On 64-bit processors, the entries in the '''IDT''' are 16 bytes long and form a table like this:
 
{|class="wikitable"
<pre>
|+Interrupt Descriptor Table (64-bit)
Table: Address:
! Address !! Content
┏━━━━━━━━━━━┓
|-
┃ Entry 0 ┃ IDTR Offset + 0
| IDTR Offset + 0 || Entry 0
┠───────────┨
|-
┃ Entry 1 ┃ IDTR Offset + 16
| IDTR Offset + 16 || Entry 1
┠───────────┨
|-
┃ Entry 2 ┃ IDTR Offset + 32
| IDTR Offset + 32 || Entry 2
┠───────────┨
|- style="text-align: center;"
┃ ... ┃ ...
| '''...''' || '''...'''
┠───────────┨
|-
┃ Entry 255 ┃ IDTR Offset + 4080
| IDTR Offset + 4080 || Entry 255
┗━━━━━━━━━━━┛
|}
</pre>
 
The corresponding entry for a given '''Interrupt Vector''' is pointed to in memory by scaling the vector by 16 and adding it to the value in the '''Offset''' field of the '''IDTR'''.
 
=== EntriesGate Descriptor ===
 
Each entry in the table has a complex structure:
 
{| class="wikitable"
<pre>
|+Gate Descriptor (64-bit):
64-bit INTERRUPT DESCRIPTOR:
!colspan="7" style="text-align: left;"|127&nbsp;&nbsp;&nbsp;<span style="float: right;">96</span>
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|-
┃127 96┃
|colspan="7" |Reserved
┠───────────────────────────────────────────────────────────────────────────────────────────────┨
|-
┃Reserved ┃
!colspan="7" style="text-align: left;"|95&nbsp;&nbsp;&nbsp;<span style="float: right;">64</span>
┃ ┃
|-
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|colspan="7" |'''Offset'''<br>63&nbsp;&nbsp;&nbsp;<span style="float: right;">32</span>
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|-
┃95 64┃
!style="width: 50%; text-align: left;"|63&nbsp;&nbsp;&nbsp;<span style="float: right;">48</span>
┠───────────────────────────────────────────────────────────────────────────────────────────────┨
!style="width: 3.125%"|47
┃Offset ┃
!style="width: 6.25%; text-align: left;"|46&nbsp;&nbsp;&nbsp;<span style="float: right;">45</span>
┃63 32┃
!style="width: 3.125%"|44
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
!style="width: 12.5%; text-align: left;"|43&nbsp;&nbsp;&nbsp;<span style="float: right;">40</span>
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━┯━━━━━┯━━┯━━━━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━┓
!style="width: 15.625%; text-align: left;"|39&nbsp;&nbsp;&nbsp;<span style="float: right;">35</span>
┃63 48│47│46 45│44│43 40│39 35│34 32┃
!style="width: 9.375%; text-align: left;"|34&nbsp;&nbsp;&nbsp;<span style="float: right;">32</span>
┠───────────────────────────────────────────────┼──┼─────┼──┼───────────┼──────────────┼────────┨
|-
┃Offset │P │DPL │0 │Gate Type │Reserved │IST ┃
|'''Offset'''<br>31&nbsp;&nbsp;&nbsp;<span style="float: right;">16</span>
┃31 16│ │1 0│ │3 0│ │2 0┃
|style="text-align: center; vertical-align: top;"|'''P'''
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━┷━━━━━┷━━┷━━━━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━┛
|'''DPL'''<br>1&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|style="text-align: center; vertical-align: top;"|0
┃31 16│15 0┃
|'''Gate Type'''<br>3&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
┠───────────────────────────────────────────────┼───────────────────────────────────────────────┨
|style="vertical-align:top"|Reserved
┃Selector │Offset ┃
|'''IST'''<br>2&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
┃15 0│15 0┃
|-
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
!style="text-align: left;" |31&nbsp;&nbsp;&nbsp;<span style="float: right;">16</span>
</pre>
!style="text-align: left;" colspan="6" |15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|-
|'''Segment Selector'''<br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|colspan="6" |'''Offset'''<br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|}
 
* '''Offset:''' A 64-bit value, split in three parts. It represents the address of the entry point of the '''[[Interrupt Service Routines|Interrupt Service Routine]]'''.
* '''Selector:''' A 16-bit'''[[Segment valueSelector]]''' with multiple fields which must point to a valid 64-bit code segment in your '''[[GDT]]'''. For more information, see '''Section 3.4.2: Segment Selectors''' and '''Figure 3-6: Segment Selector''' of the Intel Software Developer Manual, Volume 3-A.
* '''IST:''' A 3-bit value which is an offset into the '''Interrupt Stack Table''', which is stored in the '''[[Task State Segment]]'''. If the bits are all set to zero, the '''Interrupt Stack Table''' is not used.
* '''Gate Type:''' A 4-bit value which defines the type of gate this '''Interrupt Descriptor''' represents. In long mode there are two valid type values:
Line 179 ⟶ 190:
C Struct:
 
<sourcesyntaxhighlight lang="c">
struct InterruptDescriptor64 {
uint16_t offset_1; // offset bits 0..15
Line 189 ⟶ 200:
uint32_t zero; // reserved
};
</syntaxhighlight>
</source>
 
Example ''type_attributes'' values that people are likely to use (assuming DPL is 0):
Line 201 ⟶ 212:
=== Interrupt Gate ===
 
An '''Interrupt Gate''' is used to specify an '''[[Interrupt Service Routines|Interrupt Service Routine]]'''. For example, when the assembly instruction '''INT 50''' is performed while running in protected mode, the CPU looks up the 50th entry (located at 50 * 8) in the '''IDT'''. Then the Interrupt Gate's '''Selector''' and '''Offset''' values are loaded. The '''Selector''' and '''Offset''' are used to call the '''Interrupt Service Routine'''. When the '''IRET''' instruction is performed, the CPU returns from the interrupt. If the CPU was running in 32-bit mode and the specified selector is a 16-bit gate, then the CPU will go in 16-bit '''Protected Mode''' after calling the '''ISR'''. To return in this case, the '''O32 IRET''' instruction should be used, or else the CPU will not know that it should do a 32-bit return (reading 32-bit values off the [[stack]] instead of 16 bit).
 
=== Trap Gate ===