david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[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>
This commit is contained in:
Michael Brown 2014-04-28 21:11:04 +01:00
parent 23b671daf4
commit aaf276ccd4
4 changed files with 5 additions and 133 deletions

View File

@ -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;

View File

@ -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 );

View File

@ -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 ) );
}

View File

@ -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