[SeaBIOS] FreeBSD VESA console not working with SeaBIOS

Jon Doe tuksgig at gmail.com
Thu Apr 9 23:32:25 CEST 2015


On Thu, Apr 9, 2015 at 6:54 PM, Kevin O'Connor <kevin at koconnor.net> wrote:
> On Thu, Apr 09, 2015 at 09:56:07AM -0400, Kevin O'Connor wrote:
>> On Wed, Apr 08, 2015 at 10:32:23PM -0400, Kevin O'Connor wrote:
>> > The problem is not with leal in hand written assembler - the problem
>> > is with leal instructions generated by gcc.  To see the assembler gcc
>> > produces for the vgabios one can look at out/vgaccode16.raw.s .  Or,
>> > alternatively, one can run:
>> >   objdump -m i386 -M i8086 -M suffix -ldr out/vgarom.o
>> >
>> > We've fixed up gcc assembler in the past (see scripts/vgafixup.py) to
>> > work around x86emu.  However, the leal instruction seems painful to
>> > patch out - particularly so when %esp is one of the registers read or
>> > written in the leal instruction.  If anyone wants to take a stab
>> > at a workaround, feel free to submit a patch.
>>
>> It occurred to me that it might be possible to replace the leal
>> instruction with a function call.  The generic form of leal is:
>>
>>   leal $offset(%base, %index, $scale), %destination
>>
>> which does:
>>
>>   %destination = $offset + %base + (%index * $scale)
>>
>> if the above is found in the gcc assembler it could be replaced with
>> something like:
>>
>>   pushl %base
>>   pushl %index
>>   pushl $offset
>>   pushl $scale
>>   callw fake_leal
>>   popl %destination
>>
>> (The fake_leal assembler function that performs the actual calculation
>> would also need to be written.)  The above wouldn't work if %index is
>> %esp, but I don't think that would happen in practice.
>>
>> I'm not going to tackle the above right now, but maybe someone else is
>> interested in attempting it.  A word of caution though - I know leal
>> doesn't work in very old x86emu versions, but it's unclear if any
>> other gcc produced instructions are also broken.  The leal instruction
>> might just be one of many instructions that don't work.
>
> I gave it a shot anyway - seabios patch is below.
>
> It's incredibly ugly.  But, it does allow FC11 and FC12 to boot into
> graphics which wasn't possible before.  Also, I don't see any
> indication in the x86emu commit logs (
> http://anongit.freedesktop.org/git/xorg/xserver.git ) that any other
> instructions besides leal will present a problem.
>
> -Kevin
>
>
> commit c900162603f19552ec8ad3648bbb71f2effc227d
> Author: Kevin O'Connor <kevin at koconnor.net>
> Date:   Thu Apr 9 11:59:41 2015 -0400
>
>     vgabios: Hack for leal emulation
>
>     Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
>
> diff --git a/scripts/vgafixup.py b/scripts/vgafixup.py
> index a981bbf..f32c055 100644
> --- a/scripts/vgafixup.py
> +++ b/scripts/vgafixup.py
> @@ -8,19 +8,26 @@
>  # The x86emu code widely used in Linux distributions when running Xorg
>  # in vesamode is known to have issues with "retl", "leavel", "entryl",
>  # and some variants of "calll".  This code modifies those instructions
> -# (ret and leave) that are known to be generated by gcc to avoid
> -# triggering the x86emu bugs.
> +# that are known to be generated by gcc to avoid triggering the x86emu
> +# bugs.  It also translates "leal" instructions into a function call
> +# that emulates it at runtime.
>
>  # It is also known that the Windows vgabios emulator has issues with
>  # addressing negative offsets to the %esp register.  That has been
>  # worked around by not using the gcc parameter "-fomit-frame-pointer"
>  # when compiling.
>
> -import sys
> +import sys, re
>
>  def main():
>      infilename, outfilename = sys.argv[1:]
>      infile = open(infilename, 'r')
> +    re_leal = re.compile(
> +        r'^(?P<offset>[^(]*)\('
> +        r'(?P<base>[^,)]*)'
> +        r'(?:,(?P<index>[^,)]*))?'
> +        r'(?:,(?P<scale>[^,)]*))?\)'
> +        r', (?P<dest>.*)$')
>      out = []
>      for line in infile:
>          sline = line.strip()
> @@ -30,6 +37,25 @@ def main():
>              out.append('movl %ebp, %esp ; popl %ebp\n')
>          elif sline.startswith('call'):
>              out.append('pushw %ax ; callw' + sline[4:] + '\n')
> +        elif sline.startswith('leal'):
> +            m = re_leal.match(sline[5:])
> +            if m is None or m.group('index') == '%esp':
> +                print("Invalid leal instruction: %s" % (sline,))
> +                sys.exit(-1)
> +            offset, base, index, scale, dest = m.group(
> +                'offset', 'base', 'index', 'scale', 'dest')
> +            if not offset:
> +                offset = '0'
> +            if not base:
> +                base = '$0'
> +            if not index:
> +                index = '$0'
> +            if not scale:
> +                scale = '1'
> +            scale = {'1': 0, '2': 1, '4': 2, '8': 3}[scale]
> +            out.append('pushl %s ; pushl %s ; pushl $%s ; pushw $%d'
> +                       ' ; callw fake_leal ; popl %s\n' % (
> +                           base, index, offset, scale, dest))
>          else:
>              out.append(line)
>      infile.close()
> diff --git a/vgasrc/vgaentry.S b/vgasrc/vgaentry.S
> index e0ab954..21128c5 100644
> --- a/vgasrc/vgaentry.S
> +++ b/vgasrc/vgaentry.S
> @@ -45,31 +45,32 @@ _rom_header_signature:
>   * Entry points
>   ****************************************************************/
>
> -        // Force a fault if found to be running on broken x86emu versions.
> -        DECLFUNC x86emu_fault
> -msg:    .ascii "SeaVGABIOS: x86emu leal trap!\n"
> -x86emu_fault:
> -#if CONFIG_DEBUG_IO
> -        movw %cs:DebugOutputPort, %dx
> -        movw $msg, %si
> -1:      movb %cs:(%si), %al
> -        outb %al, (%dx)
> -        incw %si
> -        cmpw $x86emu_fault, %si
> -        jl 1b
> -#endif
> -1:      hlt
> -        jmp 1b
> +        // Emulate a leal instruction (see scripts/vgafixup.py)
> +        // On entry stack contains: base, index, offset, scale
> +        DECLFUNC fake_leal
> +        .global fake_leal
> +fake_leal:
> +        pushl %ebp
> +        movl %esp, %ebp
> +        pushfl
> +        pushl %eax
> +        pushl %ecx
> +
> +        movb 6(%ebp), %cl
> +        movl 12(%ebp), %eax
> +        shll %cl, %eax
> +        addl 8(%ebp), %eax
> +        addl %eax, 16(%ebp)
> +
> +        popl %ecx
> +        popl %eax
> +        popfl
> +        popl %ebp
> +        retw $10
>
>          // This macro implements a call while avoiding instructions
>          // that old versions of x86emu have problems with.
>          .macro VGA_CALLL cfunc
> -        // Make sure leal instruction works.
> -        movl $0x8000, %ecx
> -        leal (%ecx, %ecx, 1), %ecx
> -        cmpl $0x10000, %ecx
> -        jne x86emu_fault
> -        // Use callw instead of calll
>          push %ax
>          callw \cfunc
>          .endm

I can report that this patch also works for FreeBSD 8.2's VESA
console. There seems to be some unrelated problem when running
1.8-stable so I applied it to rel-1.7.5.2



More information about the SeaBIOS mailing list