Browse Source

[librm] Allow for the PIC interrupt vector offset to be changed

Some external code (observed with FreeBSD's bootloader) will continue
to make INT 13 calls after reconfiguring the 8259 PIC to change the
vector offsets for IRQs.  If an IRQ (e.g. the timer IRQ) subsequently
occurs while iPXE is in protected mode, this will cause a general
protection fault since the corresponding IDT entry is empty.

A general protection fault is INT 0x0d, which happens to overlap with
the original IRQ5.  We therefore do have an ISR set up to handle a
general protection fault, but this ISR simply reflects the interrupt
down to the real-mode INT 0x0d and then attempts to return.  Since our
ISR is expecting a hardware interrupt rather than a general protection
fault, it doesn't remove the error code from the stack before issuing
the iret instruction; it therefore attempts to return to a garbage
address.  Since the segment part of this address is likely to be
invalid, a second general protection fault occurs.  This cycle
continues until we run out of stack space and triple fault.

Fix by reflecting all INTs down to real mode.  This actually reduces
the code size by four bytes (but increases the bss size by almost
2kB).

Reported-by: Brian Rak <dn@devicenull.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
f3d423b26b
1 changed files with 6 additions and 5 deletions
  1. 6
    5
      src/arch/i386/transitions/librm_mgmt.c

+ 6
- 5
src/arch/i386/transitions/librm_mgmt.c View File

21
 extern char interrupt_wrapper[];
21
 extern char interrupt_wrapper[];
22
 
22
 
23
 /** The interrupt vectors */
23
 /** The interrupt vectors */
24
-static struct interrupt_vector intr_vec[ IRQ_MAX + 1 ];
24
+static struct interrupt_vector intr_vec[NUM_INT];
25
 
25
 
26
 /** The interrupt descriptor table */
26
 /** The interrupt descriptor table */
27
 struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) ));
27
 struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) ));
90
  */
90
  */
91
 void init_idt ( void ) {
91
 void init_idt ( void ) {
92
 	struct interrupt_vector *vec;
92
 	struct interrupt_vector *vec;
93
-	unsigned int irq;
94
 	unsigned int intr;
93
 	unsigned int intr;
95
 
94
 
96
 	/* Initialise the interrupt descriptor table and interrupt vectors */
95
 	/* Initialise the interrupt descriptor table and interrupt vectors */
97
-	for ( irq = 0 ; irq <= IRQ_MAX ; irq++ ) {
98
-		intr = IRQ_INT ( irq );
99
-		vec = &intr_vec[irq];
96
+	for ( intr = 0 ; intr < NUM_INT ; intr++ ) {
97
+		vec = &intr_vec[intr];
100
 		vec->pushal = PUSHAL_INSN;
98
 		vec->pushal = PUSHAL_INSN;
101
 		vec->movb = MOVB_INSN;
99
 		vec->movb = MOVB_INSN;
102
 		vec->intr = intr;
100
 		vec->intr = intr;
105
 				( uint32_t ) vec->next );
103
 				( uint32_t ) vec->next );
106
 		set_interrupt_vector ( intr, vec );
104
 		set_interrupt_vector ( intr, vec );
107
 	}
105
 	}
106
+	DBGC ( &intr_vec[0], "INTn vector at %p+%xn (phys %#lx+%xn)\n",
107
+	       intr_vec, sizeof ( intr_vec[0] ),
108
+	       virt_to_phys ( intr_vec ), sizeof ( intr_vec[0] ) );
108
 
109
 
109
 	/* Initialise the interrupt descriptor table register */
110
 	/* Initialise the interrupt descriptor table register */
110
 	idtr.base = virt_to_phys ( idt );
111
 	idtr.base = virt_to_phys ( idt );

Loading…
Cancel
Save