#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
*
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 */
"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 */
:
:
/**
- * 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;
-
- /* 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 );
+ int rc;
+
+ 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;
#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
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 );
.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:
/* 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 */
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