[SeaBIOS] [PATCH 1/2] Don't pass return address to transition(32, 16, 16big) on stack.

Kevin O'Connor kevin at koconnor.net
Wed Dec 8 03:46:10 CET 2010


On Tue, Dec 07, 2010 at 05:14:11PM -0800, H. Peter Anvin wrote:
> First of all, sorry for the very late reply, however, I thought I really
> ought to offer my perspective on this:
> 
> On 11/25/2010 06:24 AM, Kevin O'Connor wrote:
> > It's difficult to have a uniform view of the stack when transition
> > modes, so pass the return address in a register.  As a result, the
> > transition functions only access memory via the %cs selector now.
> 
> I think this assertion is rather unfortunate, because my own experience
> with thunking is that it is actually a very useful thing to have access
> to the real-mode stack.
> 
> This is simply accomplished by computing a 32-bit register containing
> the value (ss << 4) + sp, for example:
> 
> 	movzwl	%sp, %eax
> 	movl	%ss, %ecx
> 	shrl	$4, %ecx
> 	addl	%ecx, %eax

This is basically what the stacks.c:call32() code does.

> This is particularly handy if there is a push/pop of the 16-bit register
> set in the entry/exit sequence.  Furthermore, pushing the target address
> onto the stack rather than stuffing it into a register allows a 32-bit
> routine to have full access to the 16-bit register image, whereas
> burning a register means that that register is going to have to be
> handled differently.
> 
> In Syslinux I have this formalized so that the sequence:
> 
> 	pushl	$func32
> 	callw	_pm_call

This is similar to what SeaBIOS used to do - it had: "pushl $func32;
jmp transition32" and "pushl $func16; jmp transition16".

The problem with this is that I can't use "popl" to get the
destination address in transition16 because a popl in 16bit mode only
looks at %sp and not %esp.  So, if %esp==0x90000 and I do "pushl
$func16; transition16", then when transition16 does a "retl" (or
"popl") then it ends up pulling the address at 0x0000 instead of
0x90000.

You might ask why transition16 doesn't restore %ss/%sp - but that's
what the caller (stacks.c:call32) does.  So, the real mode stack is
available, it's just not the task of transition16.

[...]
> typedef struct {
>     uint16_t gs;                /* Offset  0 */
>     uint16_t fs;                /* Offset  2 */
[...]
>     reg32_t eflags;             /* Offset 40 */
> } com32sys_t;

That's basically the same thing as SeaBIOS's "struct bregs" in
bregs.h.  The 16bit entry points back up the register state, pass it
into the C code (which can then modify the registers if needed), and
then restore the register state on return.

[...]
> _pm_call:
[...]
>                 mov ebx,.pm
>                 mov ds,ax
>                 jmp enter_pm

This looks very similar to what SeaBIOS has now - _pm_call is the
equivalent of the inline asm in call32() and enter_pm is the
equivalent of transtion32.  See:

http://git.linuxtogo.org/?p=kevin/seabios.git;a=blob;f=src/stacks.c;h=c77ba1fd9e2c5eb1e49fe60d84d54160e5b2b091;hb=HEAD#l39

and:

http://git.linuxtogo.org/?p=kevin/seabios.git;a=blob;f=src/romlayout.S;h=d83f337101e818459b8f7d76a42c52b8623a4d78;hb=HEAD#l28

-Kevin



More information about the SeaBIOS mailing list