diff options
author | Michael Brown | 2014-04-28 21:17:15 +0200 |
---|---|---|
committer | Michael Brown | 2014-04-29 19:24:04 +0200 |
commit | 23b671daf490acaec6fdad55f2bfa44021200a63 (patch) | |
tree | d457aaccd7b8764494b932fbf59b412a85878298 /src/arch/i386/transitions/librm.S | |
parent | [build] Allow for a debug level of zero (diff) | |
download | ipxe-23b671daf490acaec6fdad55f2bfa44021200a63.tar.gz ipxe-23b671daf490acaec6fdad55f2bfa44021200a63.tar.xz ipxe-23b671daf490acaec6fdad55f2bfa44021200a63.zip |
[librm] Allow interrupts in protected mode
When running in a virtual machine, switching to real mode may be
expensive. Allow interrupts to be enabled while in protected mode and
reflected down to the real-mode interrupt handlers.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch/i386/transitions/librm.S')
-rw-r--r-- | src/arch/i386/transitions/librm.S | 55 |
1 files changed, 48 insertions, 7 deletions
diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S index b5affdb8..0e550def 100644 --- a/src/arch/i386/transitions/librm.S +++ b/src/arch/i386/transitions/librm.S @@ -128,10 +128,15 @@ init_librm: addr32 leal (%eax, %edi), %ebx movl %ebx, rm_data16 - /* Set GDT and IDT base */ + /* Set GDT base */ movl %eax, gdt_base addl $gdt, gdt_base - call idt_init + + /* Initialise IDT */ + pushl $init_idt + pushw %cs + call prot_call + popl %eax /* discard */ /* Restore registers */ negl %edi @@ -141,14 +146,12 @@ init_librm: .section ".text16", "ax", @progbits .code16 - .weak idt_init set_seg_base: 1: movw %ax, 2(%bx) rorl $16, %eax movb %al, 4(%bx) movb %ah, 7(%bx) roll $16, %eax -idt_init: /* Reuse the return opcode here */ ret /**************************************************************************** @@ -237,10 +240,8 @@ real_to_prot: /* Return to virtual address */ ret - /* Default IDTR with no interrupts */ + /* Default real-mode interrupt descriptor table */ .section ".data16", "aw", @progbits - .weak idtr -idtr: rm_idtr: .word 0xffff /* limit */ .long 0 /* base */ @@ -537,6 +538,46 @@ flatten_dummy: ret /**************************************************************************** + * Interrupt wrapper + * + * Used by the protected-mode interrupt vectors to call the + * interrupt() function. + * + * May be entered with either physical or virtual stack segment. + **************************************************************************** + */ + .globl interrupt_wrapper +interrupt_wrapper: + /* Preserve segment registers and original %esp */ + pushl %ds + pushl %es + pushl %fs + pushl %gs + pushl %ss + pushl %esp + + /* Switch to virtual addressing */ + call _intr_to_virt + + /* Expand IRQ number to whole %eax register */ + movzbl %al, %eax + + /* Call interrupt handler */ + call interrupt + + /* Restore original stack and segment registers */ + lss (%esp), %esp + popl %ss + popl %gs + popl %fs + popl %es + popl %ds + + /* Restore registers and return */ + popal + iret + +/**************************************************************************** * Stored real-mode and protected-mode stack pointers * * The real-mode stack pointer is stored here whenever real_to_prot |