From 423c350f976ed2fb7c9ef40601de46dddec3236f Mon Sep 17 00:00:00 2001
From: Kevin O'Connor <kevin@koconnor.net>
Date: Thu, 9 Apr 2015 17:20:16 -0400
Subject: [PATCH 2/2] vgabios: Emulate "leal" instruction

Emulate the "leal" instruction so that the vgabios can run on older
versions of x86emu.  (This removes the previous "leal" trap.)

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
(cherry picked from commit 0b2165d191f51ed2a522142c3ed3db55bc852627)
Signed-off-by: Bruce Rogers <brogers@suse.com>
---
 scripts/vgafixup.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 vgasrc/vgaentry.S   | 24 +--------------------
 2 files changed, 59 insertions(+), 26 deletions(-)

diff --git a/scripts/vgafixup.py b/scripts/vgafixup.py
index a981bbf..2053cd5 100644
--- a/scripts/vgafixup.py
+++ b/scripts/vgafixup.py
@@ -7,8 +7,8 @@
 
 # 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
+# "leal", and some variants of "calll".  This code modifies those
+# instructions that are known to be generated by gcc to avoid
 # triggering the x86emu bugs.
 
 # It is also known that the Windows vgabios emulator has issues with
@@ -16,7 +16,59 @@
 # worked around by not using the gcc parameter "-fomit-frame-pointer"
 # when compiling.
 
-import sys
+import sys, re
+
+# leal parameter regex - example string: -3(%edx,%eax,8), %eax
+re_leal = re.compile(
+    r'^\s*(?P<offset>[^(]*?)\s*'
+    r'\(\s*(?P<base>[^,)]*?)\s*(?:,\s*(?P<index>[^,)]*?)\s*)?'
+    r'(?:,\s*(?P<scale>[^,)]*?)\s*)?\)\s*'
+    r',\s*(?P<dest>.*?)\s*$')
+
+# Find an alternate set of instructions for a given "leal" instruction
+def handle_leal(sline):
+    m = re_leal.match(sline[5:])
+    if m is None or m.group('index') == '%esp':
+        print("Unable to fixup leal instruction: %s" % (sline,))
+        sys.exit(-1)
+    offset, base, index, scale, dest = m.group(
+        'offset', 'base', 'index', 'scale', 'dest')
+    if dest == '%esp':
+        # If destination is %esp then just use 16bit leaw instead
+        return 'leaw %s\n' % (sline[5:].replace('%e', '%'),)
+    if not scale:
+        scale = '1'
+    scale = {1: 0, 2: 1, 4: 2, 8: 3}[int(scale, 0)]
+    # Try to rearrange arguments to simplify 'base' (to improve code gen)
+    if not scale and base == index:
+        base, index, scale = '', index, 1
+    elif not index or (not scale and base in (dest, '%esp') and index != dest):
+        base, index, scale = index, base, 0
+    # Produce instructions to calculate "leal"
+    insns = ['pushfw']
+    if base != dest:
+        # Calculate "leal" directly in dest register
+        if index != dest:
+            insns.insert(0, 'movl %s, %s' % (index, dest))
+        if scale:
+            insns.append('shll $%d, %s' % (scale, dest))
+        if base:
+            if base == '%esp':
+                offset += '+2'
+            insns.append('addl %s, %s' % (base, dest))
+    elif base == index:
+        # Use "imull" method
+        insns.append('imull $%d, %s' % ((1<<scale)+1, dest))
+    else:
+        # Backup/restore index register and do scaling in index register
+        insns.append('pushl %s' % (index,))
+        insns.append('shll $%d, %s' % (scale, index))
+        insns.append('addl %s, %s' % (index, dest))
+        insns.append('popl %s' % (index,))
+    if offset and offset != '0':
+        insns.append('addl $%s, %s' % (offset, dest))
+    insns.append('popfw\n')
+    return ' ; '.join(insns)
 
 def main():
     infilename, outfilename = sys.argv[1:]
@@ -30,6 +82,9 @@ 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'):
+            out.append(handle_leal(sline))
+            #print("-> %s\n   %s" % (sline, out[-1].strip()))
         else:
             out.append(line)
     infile.close()
diff --git a/vgasrc/vgaentry.S b/vgasrc/vgaentry.S
index dbb75e4..d9ebdb9 100644
--- a/vgasrc/vgaentry.S
+++ b/vgasrc/vgaentry.S
@@ -45,33 +45,11 @@ _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
-
         // This macro implements a call while avoiding instructions
         // that old versions of x86emu have problems with.
         .macro VGA_CALLL cfunc
 #if CONFIG_VGA_FIXUP_ASM
-        // 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
+        pushw %ax
         callw \cfunc
 #else
         calll \cfunc
-- 
1.9.0

