diff options
author | Michael Brown | 2006-05-06 21:44:23 +0200 |
---|---|---|
committer | Michael Brown | 2006-05-06 21:44:23 +0200 |
commit | fdb983d47383254aebe91edb22b87f18baf0b399 (patch) | |
tree | 09825a4f2cc6e1b92a22e8e45a3d69c334ef907b /src | |
parent | Allow access to variables in .text16 as well as .data16. Chained (diff) | |
download | ipxe-fdb983d47383254aebe91edb22b87f18baf0b399.tar.gz ipxe-fdb983d47383254aebe91edb22b87f18baf0b399.tar.xz ipxe-fdb983d47383254aebe91edb22b87f18baf0b399.zip |
Preserve the whole of %esp across prot_call(). We have to split this
between the low half stored in the static variable rm_sp, and the high
half stored on the prot_call() stack, because:
Just using the stack would screw up when a prot_call()ed routine
executes a real_call(); it would have no way to find the current top of
the RM stack.
Extending rm_sp to rm_esp would not be safe, because the guarantee that
rm_sp must return to the correct value by the time an external
real-mode call returns applies only to %sp, not to %esp.
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/i386/transitions/librm.S | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/src/arch/i386/transitions/librm.S b/src/arch/i386/transitions/librm.S index 331e6215..daa2e12d 100644 --- a/src/arch/i386/transitions/librm.S +++ b/src/arch/i386/transitions/librm.S @@ -229,10 +229,11 @@ real_to_prot: * * Switch from 32-bit protected mode with virtual addresses to 16-bit * real mode. The protected-mode %esp is stored in pm_esp and the - * real-mode %ss:sp is restored from the saved rm_ss and rm_sp. All - * real-mode data segment registers are loaded from the saved rm_ds. - * Interrupts are *not* enabled, since we want to be able to use - * prot_to_real in an ISR. All other registers may be destroyed. + * real-mode %ss:sp is restored from the saved rm_ss and rm_sp. The + * high word of the real-mode %esp is set to zero. All real-mode data + * segment registers are loaded from the saved rm_ds. Interrupts are + * *not* enabled, since we want to be able to use prot_to_real in an + * ISR. All other registers may be destroyed. * * The return address for this function should be a 32-bit (sic) * real-mode offset within .code16. @@ -284,7 +285,7 @@ p2r_jump_target: /* Set up real-mode stack */ movw %bp, %ss - movw %dx, %sp + movl %edx, %esp /* Set up real-mode data segments */ movw %cs:rm_ds, %ax @@ -321,7 +322,7 @@ rm_ds: .word 0 * * All registers will be preserved across prot_call(), unless the C * function explicitly overwrites values in ix86. Interrupt status - * will also be preserved. Gate A20 will be enabled. + * and GDT will also be preserved. Gate A20 will be enabled. * * Parameters: * function : virtual address of protected-mode function to call @@ -384,7 +385,9 @@ prot_call: .section ".text16" .code16 1: - /* Reload GDT, restore registers and flags and return */ + /* Reload GDT, restore registers and flags and return. Note + * that %esp is restored manually, since popal discards it. + */ movw %sp, %bp lgdt (%bp) addw $12, %sp /* also skip %cs and %ss */ @@ -393,6 +396,10 @@ prot_call: popw %fs popw %gs popal + movl -20(%esp), %esp /* -20(%sp) is not a valid 80386 expression. + * -20(%esp) is safe because prot_to_real + * zeroes the high word of %esp, and interrupts + * are still disabled at this point. */ popfl data32 ret |