[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