aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2012-05-28 13:59:07 -0400
committerKevin O'Connor <kevin@koconnor.net>2012-05-28 23:42:13 -0400
commitbeeabd63df5ad76c74360626549b0be2f6bbad91 (patch)
tree37ef0a8293d1ab589f7519e59516eb57127c8c60
parentbf2e8c2a304c1aafc612e89deaaa6066d6cdb3f6 (diff)
downloadseabios-beeabd63df5ad76c74360626549b0be2f6bbad91.tar.gz
Automatically hop off the extra stack when far calling 16bit code.
Update the low level __farcall16 code to support a 'struct bregs' in a segment other than the stack segment. Automatically hop back from the extra stack on any farcall16() calls. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
-rw-r--r--src/romlayout.S69
-rw-r--r--src/stacks.c7
2 files changed, 40 insertions, 36 deletions
diff --git a/src/romlayout.S b/src/romlayout.S
index 676658fe..147cd3bd 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -128,56 +128,61 @@ transition16big:
jmpl *%edx
// Far call a 16bit function from 16bit mode with a specified cpu register state
-// %eax = address of struct bregs
+// %es:%eax = address of struct bregs
// Clobbers: %e[bcd]x, %e[ds]i, flags
DECLFUNC __farcall16
__farcall16:
// Save %eax, %ebp
pushl %ebp
pushl %eax
+ pushl %es
// Setup for iretw call
pushw %cs
- pushw $1f // return point
- pushw BREGS_flags(%eax) // flags
- pushl BREGS_code(%eax) // CS:IP
+ pushw $1f // return point
+ pushw %es:BREGS_flags(%eax) // flags
+ pushl %es:BREGS_code(%eax) // CS:IP
// Load calling registers.
- movl BREGS_edi(%eax), %edi
- movl BREGS_esi(%eax), %esi
- movl BREGS_ebp(%eax), %ebp
- movl BREGS_ebx(%eax), %ebx
- movl BREGS_edx(%eax), %edx
- movl BREGS_ecx(%eax), %ecx
- movw BREGS_es(%eax), %es
- movw BREGS_ds(%eax), %ds
- movl %ss:BREGS_eax(%eax), %eax
+ movl %es:BREGS_edi(%eax), %edi
+ movl %es:BREGS_esi(%eax), %esi
+ movl %es:BREGS_ebp(%eax), %ebp
+ movl %es:BREGS_ebx(%eax), %ebx
+ movl %es:BREGS_edx(%eax), %edx
+ movl %es:BREGS_ecx(%eax), %ecx
+ movw %es:BREGS_ds(%eax), %ds
+ pushl %es:BREGS_eax(%eax)
+ movw %es:BREGS_es(%eax), %es
+ popl %eax
// Invoke call
- iretw // XXX - just do a lcalll
+ iretw // XXX - just do a lcalll
1:
- // Store flags, eax, ecx
+ // Store flags, es, eax
pushfw
+ cli
+ cld
+ pushw %es
pushl %eax
- movl 0x06(%esp), %eax
- movl %ecx, %ss:BREGS_ecx(%eax)
- movw %ds, %ss:BREGS_ds(%eax)
- movw %ss, %cx
- movw %cx, %ds // Restore %ds == %ss
- popl %ecx
- movl %ecx, BREGS_eax(%eax)
- popw %cx
- movw %cx, BREGS_flags(%eax)
+ movw 0x08(%esp), %es
+ movl 0x0c(%esp), %eax
+ popl %es:BREGS_eax(%eax)
+ popw %es:BREGS_es(%eax)
+ popw %es:BREGS_flags(%eax)
// Store remaining registers
- movw %es, BREGS_es(%eax)
- movl %edi, BREGS_edi(%eax)
- movl %esi, BREGS_esi(%eax)
- movl %ebp, BREGS_ebp(%eax)
- movl %ebx, BREGS_ebx(%eax)
- movl %edx, BREGS_edx(%eax)
-
- // Remove %eax, restore %ebp
+ movl %edi, %es:BREGS_edi(%eax)
+ movl %esi, %es:BREGS_esi(%eax)
+ movl %ebp, %es:BREGS_ebp(%eax)
+ movl %ebx, %es:BREGS_ebx(%eax)
+ movl %edx, %es:BREGS_edx(%eax)
+ movl %ecx, %es:BREGS_ecx(%eax)
+ movw %ds, %es:BREGS_ds(%eax)
+ movw %ss, %cx
+ movw %cx, %ds // Restore %ds == %ss
+
+ // Remove %es/%eax, restore %ebp
+ popl %eax
popl %eax
popl %ebp
diff --git a/src/stacks.c b/src/stacks.c
index febd8bc3..cfdd68de 100644
--- a/src/stacks.c
+++ b/src/stacks.c
@@ -195,10 +195,8 @@ _farcall16(struct bregs *callregs)
ASSERT16();
asm volatile(
"calll __farcall16\n"
- "cli\n"
- "cld"
: "+a" (callregs), "+m" (*callregs)
- :
+ : "m" (__segment_ES)
: "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
}
@@ -206,7 +204,8 @@ inline void
farcall16(struct bregs *callregs)
{
if (MODE16) {
- _farcall16(callregs);
+ SET_SEG(ES, GET_SEG(SS));
+ stack_hop_back((u32)callregs, 0, _farcall16);
return;
}
extern void _cfunc16__farcall16(void);