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 <[email protected]> Date: Thu Apr 9 11:59:41 2015 -0400 vgabios: Hack for leal emulation Signed-off-by: Kevin O'Connor <[email protected]> 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 _______________________________________________ SeaBIOS mailing list [email protected] http://www.seabios.org/mailman/listinfo/seabios
