int 2eto trap into the kernel. Exceptions and interrupts, whether arising from external events, internal faults, or software generated using the
intinstruction, are vectored throught Interrupt Descriptor Table, the IDT. This table is located according to the contents of the processors IDT register, the IDTR, and contains 256 entries. IDT entries are interrupt gates, trap gates or task gates.
Intel architecture accepts two forms of forced flow-control branching: the interrupt and the exception. Exceptions are classified as traps, faults or aborts. Traps are restarted at the address following the address causing the trap, faults are restarted at the address of the fault, and aborts give no reliable restart address.
The usual distinction between interrupts and exceptions is that interrupts
are asynchronous whereas exceptions are synchronous. External interrupts are
clearly asynchronous. These interrupts are maskable by the value of the
Interrupt Flag in the EFLAGS register. Exceptions are not masked by this flag.
Therefore, and exception handling might cause an other exception: called a
double-fault. Although an
int 2e is often called a software
interrupt, it seems to me to be a trap: it is immune to the setting of the IF
flag and restarts at the address following the instruction address.
Whatever the source, all interrupts and exceptions vector through the same IDT based on index. If the interrupt or exception passes through an interrupt gate then the IF flag is automatically cleared. Passing through an exception gate does not change this flag. Looking below, you can see that NT's IDT uses only interrupt and task gates.
An interrupt or task gate references a new Code Segment Selector and an offset into the segment as a target address. If the protection ring of the new code segment is different from that of the current code segment, a stack switch occurs, else no stack switch occurs. The Task-State Segment (TSS) of the Intel architecture assigns to each of the higher 3 protection rings (0, 1 and 2) a Segment Selector and offset (pointer) within the segment. If a stack switch needs to occur to a higher privilege level, the new stack information is taken from the TSS.
int 2e will switch from ring 3, user mode, to ring 0, kernel
mode. Hence there will be stack switch. When an interrupt or trap gate causes a
stack switch, the old stack selector and stack pointer will be pushed on the new
stack before pushing the EFLAGS register, the old code segment selector and the
old instruction pointer. To return from an interrupt or exception, the IRET
instruction is issued. The processor can detect a change in privilege ring on
return by virtue of the privilege associated with the popped code segment
selector. If a level is changed, the process will continue popping the stack
beyond the EFLAGS to find and recover the interrupted thread's stack segment
selector and pointer.
Certain exceptions also push an Error Code under the instruction pointer. Whether this happens, and it's meaning, depend on the exception. NT pads exceptions that are without this automatic push so that all exceptions have a common stack layout.
The format of the system descriptors is a refinement of the generic format:where the segment selector and offset combine to give the target address for the call. The segment selector is an index into the GDT or LDT where the segment descriptor (type S==1) can be found for the new code segment. The offset is the address within this segment of the interrupt or exception handler.
Of the various system segment descriptors, only interrupt, trap and task gates are allowed in the IDT. The TYPE values for these are 0101 for a task gate, D110 for a interrupt gate, D111 for a trap gate, where D is 1 for 32 bit gate and 0 for a 16 bit gate.
NT traps are interrupt gates except for a few task gates. The task gates are used for machine check and other catastrophies, perhaps to preserve as accurately as possible the machine state, for the post mortum.
In kd, either
!pcr or the
r idtr can be used to
find the IDT's location. Here is a dump of my NT's IDT:
kd> !pcr PCR Processor 0 @ffdff000 NtTib.ExceptionList: 8014f09c NtTib.StackBase: 8014f380 NtTib.StackLimit: 8014c3f0 NtTib.SubSystemTib: 00000000 NtTib.Version: 00000000 NtTib.UserPointer: 00000000 NtTib.SelfTib: 00000000 SelfPcr: ffdff000 Prcb: ffdff120 Irql: 0000001c IRR: 00000000 IDR: ffff22e8 InterruptMode: 00000000 IDT: 80036400 GDT: 80036000 TSS: 8001d000 CurrentThread: 8014c1b0 NextThread: 00000000 IdleThread: 8014c1b0 *** Bad IOCTL request from an extension  kd> dd idtr 80036400 00085034 80148e00 0008517c 80148e00 80036410 005812de 00008500 00085444 8014ee00 80036420 00085598 8014ee00 000856d4 80148e00 80036430 0008582c 80148e00 00085d48 80148e00 80036440 00501338 00008500 00086088 80148e00 80036450 00086188 80148e00 000862ac 80148e00 80036460 0008659c 80148e00 0008679c 80148e00 80036470 00087194 80148e00 00087528 80148e00 kd> dd 80036480 00087628 80148e00 0008773c 80148e00 80036490 00a07528 80148500 00087528 80148e00 800364a0 00087528 80148e00 00087528 80148e00 800364b0 00087528 80148e00 00087528 80148e00 800364c0 00087528 80148e00 00087528 80148e00 800364d0 00087528 80148e00 00087528 80148e00 800364e0 00087528 80148e00 00087528 80148e00 800364f0 00087528 80148e00 00087528 80148e00 kd> dd 80036500 00080000 00000000 00080000 00000000 80036510 00080000 00000000 00080000 00000000 80036520 00080000 00000000 00080000 00000000 80036530 00080000 00000000 00080000 00000000 80036540 00080000 00000000 00080000 00000000 80036550 00084586 8014ee00 00084670 8014ee00 80036560 00084780 8014ee00 0008533c 8014ee00 80036570 00084100 8014ee00 00087528 80148e00 kd> dd 80036580 00084ffc 80018e00 00087b44 80678e00 80036590 00083844 80148e00 0008384e 80148e00 800365a0 00089dc4 805f8e00 00083862 80148e00 800365b0 0008386c 80148e00 00083876 80148e00 800365c0 00080a18 80018e00 0008388a 80148e00 800365d0 00080ba4 80628e00 00080a84 806f8e00 800365e0 00087dc4 80678e00 000838b2 80148e00 800365f0 00081dc4 806e8e00 00081404 806f8e00
Perhaps... A pointer to a table of system service tables is available in each processes EPROCESS structure. Two tables are need for GUI threads: one for the base NT services and a second to access graphics routines which previously resided outside the kernel, but are now part of the in-kernel GDI.