summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/transitions/librm.S
diff options
context:
space:
mode:
authorMichael Brown2006-05-06 21:44:23 +0200
committerMichael Brown2006-05-06 21:44:23 +0200
commitfdb983d47383254aebe91edb22b87f18baf0b399 (patch)
tree09825a4f2cc6e1b92a22e8e45a3d69c334ef907b /src/arch/i386/transitions/librm.S
parentAllow access to variables in .text16 as well as .data16. Chained (diff)
downloadipxe-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/arch/i386/transitions/librm.S')
-rw-r--r--src/arch/i386/transitions/librm.S21
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