summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/transitions/librm.S
diff options
context:
space:
mode:
authorMichael Brown2014-04-28 21:17:15 +0200
committerMichael Brown2014-04-29 19:24:04 +0200
commit23b671daf490acaec6fdad55f2bfa44021200a63 (patch)
treed457aaccd7b8764494b932fbf59b412a85878298 /src/arch/i386/transitions/librm.S
parent[build] Allow for a debug level of zero (diff)
downloadipxe-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.S55
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