On Thu, Apr 9, 2015 at 6:54 PM, Kevin O'Connor kevin@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@koconnor.net Date: Thu Apr 9 11:59:41 2015 -0400
vgabios: Hack for leal emulation Signed-off-by: Kevin O'Connor <kevin@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>[^,)]*))?\)'
out = [] for line in infile: sline = line.strip()r', (?P<dest>.*)$')
@@ -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' % (
infile.close()base, index, offset, scale, dest)) else: out.append(line)
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