[SeaBIOS] FreeBSD VESA console not working with SeaBIOS

Kevin O'Connor kevin at koconnor.net
Thu Apr 9 18:54:48 CEST 2015


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



More information about the SeaBIOS mailing list