summaryrefslogtreecommitdiff
path: root/arch/x86/lib/bios_asm.S
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2015-07-15 10:41:20 -0400
committerTom Rini <trini@konsulko.com>2015-07-15 10:41:20 -0400
commit605e15db2b54302364a2528d3c6604fbc57be846 (patch)
tree1a1e344964bff1719939183124d66a71e7ca7731 /arch/x86/lib/bios_asm.S
parent4905dfc65d9a17083727865302d2cf633c15c911 (diff)
parentf110da9984c0aa0aba9e1c4178b67b7abecf7e8d (diff)
Merge git://git.denx.de/u-boot-x86
Diffstat (limited to 'arch/x86/lib/bios_asm.S')
-rw-r--r--arch/x86/lib/bios_asm.S23
1 files changed, 23 insertions, 0 deletions
diff --git a/arch/x86/lib/bios_asm.S b/arch/x86/lib/bios_asm.S
index 4faa70e314..9dbf969373 100644
--- a/arch/x86/lib/bios_asm.S
+++ b/arch/x86/lib/bios_asm.S
@@ -246,6 +246,9 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.)
push %fs
push %gs
+ /* Save real mode SS */
+ movw %ss, %cs:__realmode_ss
+
/* Clear DF to not break ABI assumptions */
cld
@@ -258,12 +261,29 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.)
enter_protected_mode
+ /*
+ * Now we are in protected mode. We need compute the right ESP based
+ * on saved real mode SS otherwise interrupt_handler() won't get
+ * correct parameters from the stack.
+ */
+ movzwl %cs:__realmode_ss, %ecx
+ shll $4, %ecx
+ addl %ecx, %esp
+
/* Call the C interrupt handler */
movl $interrupt_handler, %eax
call *%eax
+ /* Restore real mode ESP based on saved SS */
+ movzwl %cs:__realmode_ss, %ecx
+ shll $4, %ecx
+ subl %ecx, %esp
+
enter_real_mode
+ /* Restore real mode SS */
+ movw %cs:__realmode_ss, %ss
+
/*
* Restore all registers, including those manipulated by the C
* handler
@@ -276,6 +296,9 @@ __interrupt_handler_16bit = PTR_TO_REAL_MODE(.)
popal
iret
+__realmode_ss = PTR_TO_REAL_MODE(.)
+ .word 0
+
.globl asm_realmode_code_size
asm_realmode_code_size:
.long . - asm_realmode_code