mirror of https://github.com/ipxe/ipxe.git
[comboot] Use built-in interrupt reflector
We now have the ability to handle interrupts while in protected mode, and so no longer need to set up a dedicated interrupt descriptor table while running COM32 executables. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/17/head
parent
23b671daf4
commit
aaf276ccd4
|
@ -41,13 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
#include <ipxe/init.h>
|
||||
#include <ipxe/io.h>
|
||||
|
||||
struct idt_register com32_external_idtr = {
|
||||
.limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1,
|
||||
.base = COM32_IDT
|
||||
};
|
||||
|
||||
struct idt_register com32_internal_idtr;
|
||||
|
||||
/**
|
||||
* Execute COMBOOT image
|
||||
*
|
||||
|
@ -95,8 +88,6 @@ static int com32_exec_loop ( struct image *image ) {
|
|||
unregister_image ( image );
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"sidt com32_internal_idtr\n\t"
|
||||
"lidt com32_external_idtr\n\t" /* Set up IDT */
|
||||
"movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */
|
||||
"movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */
|
||||
"call _virt_to_phys\n\t" /* Switch to flat physical address space */
|
||||
|
@ -110,8 +101,7 @@ static int com32_exec_loop ( struct image *image ) {
|
|||
"pushl $6\n\t" /* Number of additional arguments */
|
||||
"call *%6\n\t" /* Execute image */
|
||||
"cli\n\t" /* Disable interrupts */
|
||||
"call _phys_to_virt\n\t" /* Switch back to internal virtual address space */
|
||||
"lidt com32_internal_idtr\n\t" /* Switch back to internal IDT (for debugging) */
|
||||
"call _phys_to_virt\n\t" /* Switch back to internal virtual address space */
|
||||
"movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */
|
||||
:
|
||||
:
|
||||
|
@ -201,55 +191,25 @@ static int com32_identify ( struct image *image ) {
|
|||
|
||||
|
||||
/**
|
||||
* Load COM32 image into memory and set up the IDT
|
||||
* Load COM32 image into memory
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int com32_load_image ( struct image *image ) {
|
||||
physaddr_t com32_irq_wrapper_phys;
|
||||
struct idt_descriptor *idt;
|
||||
struct ijb_entry *ijb;
|
||||
size_t filesz, memsz;
|
||||
userptr_t buffer;
|
||||
int rc, i;
|
||||
int rc;
|
||||
|
||||
/* The interrupt descriptor table, interrupt jump buffer, and
|
||||
* image data are all contiguous in memory. Prepare them all at once.
|
||||
*/
|
||||
filesz = image->len +
|
||||
COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) +
|
||||
COM32_NUM_IDT_ENTRIES * sizeof ( struct ijb_entry );
|
||||
filesz = image->len;
|
||||
memsz = filesz;
|
||||
buffer = phys_to_user ( COM32_IDT );
|
||||
buffer = phys_to_user ( COM32_START_PHYS );
|
||||
if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
|
||||
DBGC ( image, "COM32 %p: could not prepare segment: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Write the IDT and IJB */
|
||||
idt = phys_to_virt ( COM32_IDT );
|
||||
ijb = phys_to_virt ( COM32_IJB );
|
||||
com32_irq_wrapper_phys = virt_to_phys ( com32_irq_wrapper );
|
||||
|
||||
for ( i = 0; i < COM32_NUM_IDT_ENTRIES; i++ ) {
|
||||
uint32_t ijb_address = virt_to_phys ( &ijb[i] );
|
||||
|
||||
idt[i].offset_low = ijb_address & 0xFFFF;
|
||||
idt[i].selector = PHYSICAL_CS;
|
||||
idt[i].flags = IDT_INTERRUPT_GATE_FLAGS;
|
||||
idt[i].offset_high = ijb_address >> 16;
|
||||
|
||||
ijb[i].pusha_instruction = IJB_PUSHA;
|
||||
ijb[i].mov_instruction = IJB_MOV_AL_IMM8;
|
||||
ijb[i].mov_value = i;
|
||||
ijb[i].jump_instruction = IJB_JMP_REL32;
|
||||
ijb[i].jump_destination = com32_irq_wrapper_phys -
|
||||
virt_to_phys ( &ijb[i + 1] );
|
||||
}
|
||||
|
||||
/* Copy image to segment */
|
||||
buffer = phys_to_user ( COM32_START_PHYS );
|
||||
memcpy_user ( buffer, 0, image->data, 0, filesz );
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -13,50 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
#include <setjmp.h>
|
||||
#include <ipxe/in.h>
|
||||
|
||||
/** Descriptor in a 32-bit IDT */
|
||||
struct idt_descriptor {
|
||||
uint16_t offset_low;
|
||||
uint16_t selector;
|
||||
uint16_t flags;
|
||||
uint16_t offset_high;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Operand for the LIDT instruction */
|
||||
struct idt_register {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Entry in the interrupt jump buffer */
|
||||
struct ijb_entry {
|
||||
uint8_t pusha_instruction;
|
||||
uint8_t mov_instruction;
|
||||
uint8_t mov_value;
|
||||
uint8_t jump_instruction;
|
||||
uint32_t jump_destination;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** The x86 opcode for "pushal" */
|
||||
#define IJB_PUSHA 0x60
|
||||
|
||||
/** The x86 opcode for "movb $imm8,%al" */
|
||||
#define IJB_MOV_AL_IMM8 0xB0
|
||||
|
||||
/** The x86 opcode for "jmp rel32" */
|
||||
#define IJB_JMP_REL32 0xE9
|
||||
|
||||
/** Flags that specify a 32-bit interrupt gate with DPL=0 */
|
||||
#define IDT_INTERRUPT_GATE_FLAGS 0x8E00
|
||||
|
||||
/** Address of COM32 interrupt descriptor table */
|
||||
#define COM32_IDT 0x100000
|
||||
|
||||
/** Number of entries in a fully populated IDT */
|
||||
#define COM32_NUM_IDT_ENTRIES 256
|
||||
|
||||
/** Address of COM32 interrupt jump buffer */
|
||||
#define COM32_IJB 0x100800
|
||||
|
||||
/** Segment used for COMBOOT PSP and image */
|
||||
#define COMBOOT_PSP_SEG 0x07C0
|
||||
|
||||
|
@ -153,7 +109,6 @@ extern void unhook_comboot_interrupts ( );
|
|||
extern void com32_intcall_wrapper ( );
|
||||
extern void com32_farcall_wrapper ( );
|
||||
extern void com32_cfarcall_wrapper ( );
|
||||
extern void com32_irq_wrapper ( );
|
||||
|
||||
/* Resolve a hostname to an (IPv4) address */
|
||||
extern int comboot_resolv ( const char *name, struct in_addr *address );
|
||||
|
|
|
@ -189,20 +189,3 @@ int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz )
|
|||
|
||||
return eax;
|
||||
}
|
||||
|
||||
/**
|
||||
* IRQ handler
|
||||
*/
|
||||
void __asmcall com32_irq ( uint32_t vector ) {
|
||||
uint32_t *ivt_entry = phys_to_virt( vector * 4 );
|
||||
|
||||
__asm__ __volatile__ (
|
||||
REAL_CODE ( "pushfw\n\t"
|
||||
"pushw %%cs\n\t"
|
||||
"pushw $com32_irq_return\n\t"
|
||||
"pushl %0\n\t"
|
||||
"lret\n"
|
||||
"com32_irq_return:\n\t" )
|
||||
: /* no outputs */
|
||||
: "r" ( *ivt_entry ) );
|
||||
}
|
||||
|
|
|
@ -23,26 +23,6 @@ FILE_LICENCE ( GPL2_OR_LATER )
|
|||
.arch i386
|
||||
.code32
|
||||
|
||||
/*
|
||||
* This code is entered after running the following sequence out of
|
||||
* the interrupt jump buffer:
|
||||
*
|
||||
* pushal
|
||||
* movb $vector, %al
|
||||
* jmp com32_irq_wrapper
|
||||
*/
|
||||
|
||||
.globl com32_irq_wrapper
|
||||
com32_irq_wrapper:
|
||||
|
||||
movzbl %al,%eax
|
||||
pushl %eax
|
||||
movl $com32_irq, %eax
|
||||
call com32_wrapper
|
||||
popl %eax
|
||||
popal
|
||||
iret
|
||||
|
||||
.globl com32_farcall_wrapper
|
||||
com32_farcall_wrapper:
|
||||
|
||||
|
@ -69,9 +49,6 @@ com32_wrapper:
|
|||
/* Switch to internal virtual address space */
|
||||
call _phys_to_virt
|
||||
|
||||
/* Switch to internal IDT (if we have one for debugging) */
|
||||
lidt com32_internal_idtr
|
||||
|
||||
mov %eax, (com32_helper_function)
|
||||
|
||||
/* Save external COM32 stack pointer */
|
||||
|
@ -99,9 +76,6 @@ com32_wrapper:
|
|||
movl %esp, (com32_internal_esp)
|
||||
movl (com32_external_esp), %esp
|
||||
|
||||
/* Switch to com32 IDT */
|
||||
lidt com32_external_idtr
|
||||
|
||||
/* Switch to external flat physical address space */
|
||||
call _virt_to_phys
|
||||
|
||||
|
|
Loading…
Reference in New Issue