Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / scripts / vgafixup.py
1 #!/usr/bin/env python
2 # Work around x86emu bugs by replacing problematic instructions.
3 #
4 # Copyright (C) 2012  Kevin O'Connor <kevin@koconnor.net>
5 #
6 # This file may be distributed under the terms of the GNU GPLv3 license.
7
8 # The x86emu code widely used in Linux distributions when running Xorg
9 # in vesamode is known to have issues with "retl", "leavel", "entryl",
10 # "leal", and some variants of "calll".  This code modifies those
11 # instructions that are known to be generated by gcc to avoid
12 # triggering the x86emu bugs.
13
14 # It is also known that the Windows vgabios emulator has issues with
15 # addressing negative offsets to the %esp register.  That has been
16 # worked around by not using the gcc parameter "-fomit-frame-pointer"
17 # when compiling.
18
19 import sys, re
20
21 # leal parameter regex - example string: -3(%edx,%eax,8), %eax
22 re_leal = re.compile(
23     r'^\s*(?P<offset>[^(]*?)\s*'
24     r'\(\s*(?P<base>[^,)]*?)\s*(?:,\s*(?P<index>[^,)]*?)\s*)?'
25     r'(?:,\s*(?P<scale>[^,)]*?)\s*)?\)\s*'
26     r',\s*(?P<dest>.*?)\s*$')
27
28 # Find an alternate set of instructions for a given "leal" instruction
29 def handle_leal(sline):
30     m = re_leal.match(sline[5:])
31     if m is None or m.group('index') == '%esp':
32         print("Unable to fixup leal instruction: %s" % (sline,))
33         sys.exit(-1)
34     offset, base, index, scale, dest = m.group(
35         'offset', 'base', 'index', 'scale', 'dest')
36     if dest == '%esp':
37         # If destination is %esp then just use 16bit leaw instead
38         return 'leaw %s\n' % (sline[5:].replace('%e', '%'),)
39     if not scale:
40         scale = '1'
41     scale = {1: 0, 2: 1, 4: 2, 8: 3}[int(scale, 0)]
42     # Try to rearrange arguments to simplify 'base' (to improve code gen)
43     if not scale and base == index:
44         base, index, scale = '', index, 1
45     elif not index or (not scale and base in (dest, '%esp') and index != dest):
46         base, index, scale = index, base, 0
47     # Produce instructions to calculate "leal"
48     insns = ['pushfw']
49     if base != dest:
50         # Calculate "leal" directly in dest register
51         if index != dest:
52             insns.insert(0, 'movl %s, %s' % (index, dest))
53         if scale:
54             insns.append('shll $%d, %s' % (scale, dest))
55         if base:
56             if base == '%esp':
57                 offset += '+2'
58             insns.append('addl %s, %s' % (base, dest))
59     elif base == index:
60         # Use "imull" method
61         insns.append('imull $%d, %s' % ((1<<scale)+1, dest))
62     else:
63         # Backup/restore index register and do scaling in index register
64         insns.append('pushl %s' % (index,))
65         insns.append('shll $%d, %s' % (scale, index))
66         insns.append('addl %s, %s' % (index, dest))
67         insns.append('popl %s' % (index,))
68     if offset and offset != '0':
69         insns.append('addl $%s, %s' % (offset, dest))
70     insns.append('popfw\n')
71     return ' ; '.join(insns)
72
73 def main():
74     infilename, outfilename = sys.argv[1:]
75     infile = open(infilename, 'r')
76     out = []
77     for line in infile:
78         sline = line.strip()
79         if sline == 'ret':
80             out.append('retw $2\n')
81         elif sline == 'leave':
82             out.append('movl %ebp, %esp ; popl %ebp\n')
83         elif sline.startswith('call'):
84             out.append('pushw %ax ; callw' + sline[4:] + '\n')
85         elif sline.startswith('leal'):
86             out.append(handle_leal(sline))
87             #print("-> %s\n   %s" % (sline, out[-1].strip()))
88         else:
89             out.append(line)
90     infile.close()
91     outfile = open(outfilename, 'w')
92     outfile.write(''.join(out))
93     outfile.close()
94
95 if __name__ == '__main__':
96     main()