Skip to content


Browse files Browse the repository at this point in the history
[callback] Provide space for a protected-mode interrupt descriptor table
We currently do not use a protected-mode interrupt descriptor table,
since we do not expect to handle interrupts or exceptions while
running in protected mode.

The Windows loader writes some entries for CPU exception handlers
within the interrupt descriptor table, locating the table via the
"sidt" instruction.  Since the IDTR contains all zeroes, the result is
that Windows ends up overwriting some vectors within the real-mode
interrupt vector table (which really is at physical address zero).

With the 64-bit version of Windows Server 2008 R2, the entries which
get overwritten include offsets 0x18 (INT 03), 0x30 (INT 06), and 0x38
(INT 07): these correspond to INT 06 (invalid opcode), INT 07 (no FPU
installed), INT 0c (IRQ 4), INT 0d (IRQ 5), INT 0e (IRQ 6), and INT 0f
(IRQ 7) in the real-mode interrupt vector table.

Somewhat astonishingly, this has generally not caused problems,
because the overwritten vectors tend to correspond to unused entries
within the real-mode table.  However, some HP systems (observed with
at least an HP DL360p Gen8) happen to enable IRQ 5 (which uses the
vector for INT 0d), and to have hardware which will generate
interrupts on that IRQ line.  On these systems, an interrupt which
occurs shortly after the interrupt descriptor table has been corrupted
will jump to the address 0028:8e00 (which is likely to contain
garbage), resulting in undefined behaviour such as a system hang,
a reboot, or a Red Screen of Death.

Fix by allocating storage for a 256-entry protected-mode interrupt
descriptor table.

Debugged-by: Fred Pedrisa <>
Debugged-by: Michael Brown <>
Signed-off-by: Michael Brown <>
  • Loading branch information
mcb30 committed Nov 7, 2014
1 parent 86f3a34 commit 1f11d05
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 9 deletions.
4 changes: 2 additions & 2 deletions src/callback.S
Expand Up @@ -137,8 +137,8 @@ call_real:
movw %gs, PARAM_GS(%bp)

/* Switch back to protected mode */
addr32 data32 lgdt %cs:( gdt - BASE_ADDRESS )
addr32 data32 lidt %cs:( idt - BASE_ADDRESS )
addr32 data32 lgdt %cs:( gdtr - BASE_ADDRESS )
addr32 data32 lidt %cs:( idtr - BASE_ADDRESS )
popl %eax
movl %eax, %cr0
data32 ljmp $FLAT_CS, $1f
Expand Down
24 changes: 17 additions & 7 deletions src/startup.S
Expand Up @@ -39,8 +39,8 @@
.globl startup
/* Reload GDT, IDT, and all segment registers, and set up stack */
lgdt gdt
lidt idt
lgdt gdtr
lidt idtr
ljmp $FLAT_CS, $1f
1: movw $FLAT_DS, %ax
movw %ax, %ds
Expand Down Expand Up @@ -74,8 +74,10 @@ reboot:

/* Global descriptor table */
.section ".rodata16", "aw", @progbits
.globl gdt
.align 8
.globl gdtr
.word gdt_limit
.long gdt
/* 64 bit long mode code segment */
Expand All @@ -102,12 +104,20 @@ gdt:
.equ gdt_limit, . - gdt - 1

/* Interrupt descriptor table */
.section ".data16", "ax", @progbits
.globl idt
.section ".bss16", "aw", @nobits
.align 8
.word 0 /* Limit */
.long 0 /* Base */
.space ( 256 * 8 ) /* 256 8-byte entries */
.size idt, . - idt
.equ idt_limit, . - idt - 1

/* Interrupt descriptor table register */
.section ".rodata16", "aw", @progbits
.globl idtr
.word idt_limit
.long idt
.size idtr, . - idtr

/* Stack */
.section ".stack", "aw", @nobits
Expand Down

0 comments on commit 1f11d05

Please sign in to comment.