[davidm@AZStarNet.com: bios executor]

David Mosberger-Tang (davidm@AZStarNet.com)
Sun, 24 Sep 1995 23:39:24 -0700


Still haven't seen this mail on linux-alpha yet, so I'm trying again
(3rd time now...).

--david

------- Start of forwarded message -------
Date: Tue, 19 Sep 1995 17:20:22 -0700
From: David Mosberger-Tang <davidm@AZStarNet.com>
To: linux-alpha@vger.rutgers.edu, davidm@AZStarNet.com
Subject: bios executor

OK, for those of you feeling adventurous, there is a new program
on my ftp site:

ftp://ftp.azstarnet.com/pub/linux/axp/sys/ginit.gz

WARNING: This program can DESTROY your monitor and possibly other
hw. I assume no responsibility if this should happen.

WARNING: This program is EXPERIMENTAL code, its not very robust
or anything.

WARNING: Do not attempt to execute this program on anything but a
Noname (AXPpci33) or Cabriolet (APC64).

As the program has to be executed as root, here the md5-checksum:

davidm@koala[x86emu] md5sum ginit
0821386077a88b223ade901bcb4f2bcd ginit

What does ginit do? Well, it simply maps the BIOS on a graphics card
and attempts to execute its initialization function (entry point
0xc0003). It has support for a *few* 386 instructions, but there is
no guarantee that it will execute your graphics card's code properly.

ginit has a couple of options:

-s num: Specifies which PCI slot the graphics card is in
(obviously required for PCI graphics cards only).
Do a "cat /proc/pci" and specify the device number
listed for your graphics card as the value of this
option. If the program cannot map/find the ROM
signature 0x55, 0xaa in the first two bytes, it
will stop and not do anything.

-d: Disassemble instructions as they are executed and
print them to stderr.

-t: Print register dump after executing each instruction.

-m: Log each memory access to stderr. The format for a
read is: ADDR SIZE -> VALUE
meaning that the emulator read VALUE at address ADDR
and that VALUE is SIZE bytes long (VALUE sometimes has
garbage in the higher-order bits; those can be ignored
safely). The format for a write is identical, except
that "<-" is printed instead of "->".

-i: Same as -m, but for I/O space accesses (inb/outb etc.).
I/O accesses are printed in the right half of the
screen, so it's easy to distinguish them from memory
accesses logged by -m.

If you want to help along with the bios emulator, I'd appreciate if
you could do the following:

(1) If you have a #9 GXE Level 12 or #9 GXE64 PCI graphics card,
you're done (I can test those myself and they work reasonably
well; if you still want to try it DO NOT attempt to select a
non-standard VGA frequency after running the initialization code
on a Level 12---the BIOS code is real-time dependent and currently
gets the clock programming wrong; as a result, selecting a non-standard
frequency will likely fry your monitor---yes, it's true---it happened to
me yesterday and it's not much fun... :( ).

(2) Turn off your monitor, log in as root via serial-line or
network, then run ginit with the appropriate "-s" option if you have
a PCI card and redirect stderr to a file. E.g., on my Noname with the
graphics card in PCI device slot 8, I'd do:

bash# ./ginit -s 8 2>log
device/vendor id=88c15333
ROM base address+1=c0001
bash#

And the log file then contains:

bash# cat log
x86_bios: interrupt 0x10 is undefined!
x86_bios: interrupt 0x1a is undefined!
x86_bios: interrupt 0x1a is undefined!
x86_bios: interrupt 0x1a is undefined!
x86_bios: interrupt 0x1a is undefined!
mem_read: address 0xffff out of range!
halted

The last "out of range" error is quite all right as it simply
means that the BIOS execution has finished (ginit currently
terminates simply by causing a stack underflow... :).

The x86_bios warnings are there because ginit doesn't really
emulate any BIOS interrupts yet. The first INT 10 is normally
to turn off video, which is not so important as you turned off
your monitor (so no damage can occur).

The INT 1A calls are more interesting. Those are calls with

AX = 0xb102

which, according to the PC book that I have, is an undefined
(well, "reserved") call. Anybody out there who knows what this
call is supposed to do?

Interestingly, despite those INT 1A calls, the #9 GXE 64 gets
initialized properly (as far as I can tell). I can even select
non-standard VGA frequencies and it all works fine. But this
may be because the graphics card was already initialized when
"ginit" started execution (thanks to the SRM console). In any
case, this certainly needs to be fixed in the future.

In the unlikely case that this all works for your graphics card,
too, let me know what graphics card it is (BIOS version might
be necessary, too) and you're done.

(3) OK, I thought there would be problems. You'll need to do some
debugging. Most likely, the BIOS uses an unimplemented
instruction. To find out what instruction it is, restart
ginit, but this time be sure to add option "-d". Depending on
how far the emulator gets, the log file may be large to HUGE.
Be sure you have enough diskspace. For example, a successful
execution of the GXE 64 PCI initialization function generates
a log file that is 6MB large. If the problem is indeed due
to an unimplemented instruction, send me the tail of the log
file. If it's not you will have to dig deeper into the emulator
(e.g., by looking at the address traces generated by "-m -i").

So, if anybody works all the way to the end of this mail and gets
some interesting results, please let me know.

One more thing: I don't think GDE is a good starting point for an x86
emulator with x>=2. I'm considering to start (more or less) from
scratch as this would actually *reduce* the amount of work to get full
386 support (real-mode only, of course). However, I think GDE is good
enough to get it to execute the common graphics-card BIOSes, so we
could use it until something better shows up.

Good luck and don't fry your monitor!

--david

------- End of forwarded message -------