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/core/virtaddr.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/core/virtaddr.S')
| -rw-r--r-- | src/arch/i386/core/virtaddr.S | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/src/arch/i386/core/virtaddr.S b/src/arch/i386/core/virtaddr.S index aae1e1edd..5e5d77352 100644 --- a/src/arch/i386/core/virtaddr.S +++ b/src/arch/i386/core/virtaddr.S @@ -36,6 +36,7 @@ _virt_to_phys: addl %ebp, 12(%esp) /* Switch to physical code segment */ + cli pushl $PHYSICAL_CS leal 1f(%ebp), %eax pushl %eax @@ -44,10 +45,10 @@ _virt_to_phys: /* Reload other segment registers and adjust %esp */ movl $PHYSICAL_DS, %eax movl %eax, %ds - movl %eax, %es - movl %eax, %fs + movl %eax, %es + movl %eax, %fs movl %eax, %gs - movl %eax, %ss + movl %eax, %ss addl %ebp, %esp /* Restore registers and flags, and return */ @@ -64,9 +65,6 @@ _virt_to_phys: * selectors. All other registers are preserved. Flags are * preserved. * - * Note that this depends on the GDT already being correctly set up - * (e.g. by a call to run_here()). - * * Parameters: none * Returns: none **************************************************************************** @@ -79,18 +77,19 @@ _phys_to_virt: pushl %ebp /* Switch to virtual code segment */ + cli ljmp $VIRTUAL_CS, $1f -1: +1: /* Reload data segment registers */ movl $VIRTUAL_DS, %eax movl %eax, %ds - movl %eax, %es - movl %eax, %fs + movl %eax, %es + movl %eax, %fs movl %eax, %gs /* Reload stack segment and adjust %esp */ movl virt_offset, %ebp - movl %eax, %ss + movl %eax, %ss subl %ebp, %esp /* Change the return address to a virtual address */ @@ -101,3 +100,46 @@ _phys_to_virt: popl %eax popfl ret + +/**************************************************************************** + * _intr_to_virt (virtual code segment, virtual or physical stack segment) + * + * Switch from virtual code segment with either a virtual or physical + * stack segment to using virtual addressing. %esp is adjusted if + * necessary to a virtual value. Segment registers are set to virtual + * selectors. All other registers are preserved. Flags are + * preserved. + * + * Parameters: none + * Returns: none + **************************************************************************** + */ + .globl _intr_to_virt +_intr_to_virt: + /* Preserve registers and flags */ + pushfl + pushl %eax + pushl %ebp + + /* Check whether stack segment is physical or virtual */ + movl %ss, %eax + cmpw $VIRTUAL_DS, %ax + movl $VIRTUAL_DS, %eax + + /* Reload data segment registers */ + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + + /* Reload stack segment and adjust %esp if necessary */ + je 1f + movl virt_offset, %ebp + movl %eax, %ss + subl %ebp, %esp +1: + /* Restore registers and flags, and return */ + popl %ebp + popl %eax + popfl + ret |
