Hey, something you might want to know? DOSEMU has everything you need to
be able to use the system's native bios, and it would then even support
SVGA. Take a look at it.

Also DOSEMU has a VGA BIOS but it's emulated at the interrupt level.
What it does is it creates a binary image that appears to be a VGA BIOS
to applications, but when you transfer control to an entrypoint, it
causes a page fault, and then native Linux code handles the interrupt 10
request.

But that is done only if you don't (or can't) use the native BIOS. With
DOSEMU, if the native BIOS gets used, then you have to specify which
chipset it is (s3, vga only, etc.); and then when the BIOS tries to
access ports, it will be intercepted and emulated only if not in
full-screen mode. For example, like the plex86 gui, xdosemu can be run
in a window.

Also DOSEMU has some VGA emulation that is more accurate then plex86's.
DOSEMU is portable, and it even has two instruction set emulators: one
is based on bochs code and one isn't.

One of the instruction set emulators gets used only on non-x86
architectures.

The other instruction set emulator gets used even on x86. When there's
an access to video memory, for example inside an x window, the access
will cause a page fault, and then the instruction set emulator will see
what that access does and emulate it; it will even continue emulating
instructions after that even if they don't access video memory. It will
stop emulating if a certain number of instructions get executed that
don't access video memory.

I think they thought it was necessary to do that, and faster than
causing a fault for each and every access to video memory. This is
especially true for string instructions, which would otherwise fault for
each iteration. I think they felt it was necessary because of CPU
latches and stuff (VGA is weird).

What does plex86 do to handle accesses to video memory? Does it
correctly handle latches?

Also I have a VGA BIOS but it was made after reverse engineering my own
s3 BIOS and I'm worried that it might be illegal to use it for
commercial purposes. Therefore, if you guys use it, the LGPL license
couldn't be void. So if you would like to use GPL, I can send it... now
it was written from scratch, but I learned how to do things by tracing
s3 BIOS and 'noticing' which ports it accessed when, and I made a
cluster map of all instructions in the BIOS and it walked through each
isntruction, like a web page bot crawler, and then when it hit a cluster
(instruction) that had already been executed, the program walks
backwords until a conditional instruction is encountered that has a
branch that was not already taken, etc.

DOing this I created a text file that mapped the whole thing and I wrote
various programs to look at what it did. There were a few "dummy" paths
that made things more complicated. For example:

STC
JC ...

My icrawler program would continue going even after that instruction,
and I had to manually remove those things. Icrawler is really dumb and
can't automatically recognize indirect control transfers to tables, so I
have to manually help it out there. But it can recognize MOV
instructions and XCHG instructions. It keeps track of the general
registers and segment registers, and by default it marks all of them as
unknown; then if there's a MOV AX,1234h it will make AX = known, 1234h;
and then if there's a MOV DS,AX; you get the idea.

For push and pop's it doesn't recognize the relivence of SS or SP. It
just matches PUSH's and POP's, which is why it requires too much manual
interaction to be practical on MS-DOS, or anything fancy for that
matter. Using it on a BIOS was easier because I can gaurentee there will
be no self-modified code.

It matches CALLs and RETs, but it doesn't notice if they are different
KINDs of calls and rets; it just assumes everything matches up (i.e. is
traditional).

Here's the general idea of what I did: I created an array of clusters
numbered 0..7fff. Each one corresponds with 1 byte of the S3 BIOS. Each
cluster is 32 bytes and by default each cluster is completely zero,
indicating that that cluster is never executed or (in general) accessed.

Then you do this: make it look at offset 3 (that's the entrypoint to the
VGA BIOS initialization code).

Each cluster has the following information: a flag, a pointer to the
next cluster after the current one, and a BRANCH. For example, for most
instructions BRANCH is not used and the next cluster pointer just points
to the next instruction. For a CALL instruction, the next cluster
pointer points to the next instruction after the call returns.

The BRANCH poinst to the entrypoint of the call.

Say:

nop
call abcd
nop
retf

abcd:
nop
ret

Now when we hit the call abcd, we load the branch and next of the
cluster corresponding with the call instruction, and then look at abcd
unless we've already been there. If you hit an END (like a HALT or
something that can't be handled, like indirect jumps), OR if you hit a
cluster you've already been at before, then you backtrack and keep going
back until a cluster is referenced in either BRANCH or NEXT that you
have NOT already been at, unless you go all the way back to the
beginning and you realize that you can't backtrack any more; then, you
are done.

Now each cluster also has a PREVIOUS_CLUSTER pointer, and that points to
the what the previous cluster was the last time the given instruction
"executed".

I don't actually execute the code, just map out all possibilities. In
general I can see which port read/writes get done since DX/AX etc. all
typically just use MOV's or XCHG's or PUSH/POP's.

So say we reach the retf in abcd. Then we walk back to the NOP, and make
the PREVIOUS_CLUSTER pointer of the RET -1 (which is the default) and do
the same for the nop. Then we're at the call to abcd. That cluster has a
NEXT and a BRANCH, and we see that we already were at the BRANCH (abcd)
but not the NEXT (the instruction after the CALL). That's a nop, and you
just keep going until you hit the RETF.

When you hit that, you backtrack: you're at the NOP before it, then the
CALL ABCD, then the NOP there. That is because the PREVIOUS_CLUSTER is
updated in a way so that you can match push/pop's and call/ret's. When
you try to go back from the nop at the top, you realize that you can't
go back any more (because that's where we entered). Then you're done.

Write the cluster map out to disk.

If you run the program again it reads the cluster map and will go
through all possibilities, but will not discover anything new, unless
you have manually helped it out (for example, you have to do that for
indirect jumps, in which case it WILL discover something new).

This way you don't actually disassemble but you create a tet file
detailing what port I/O gets done for what INT 10 function, you see what
conditions are taken (for conditional jumps you do the same thing as for
calls except the branch is for if the condition is met; for
unconditional control transfer you just go to the destination; certainly
you never cross your tracks twice, however).

I had to make some programs to parse the textfile too, to see what port
writes get made etc. It's easy to confuse this reverse engineering
program, and Intel BIOSes are good at it. I can't seem to reverse
engineer my real BIOS because it does some VERY QUEER things, like
making SS:SP point to somewhere inside F000:0000..FFFF and then doing a
RET; it does things with ESP first... too complicated ;)

I looked in vgadoc to see what it was doing. Some port writes are
suspicious, but it wasn't too bad. The result was a VGA BIOS. I haven't
added the s3-specific things yet. It didn't used to support multiple
monitors but now it does. I found ralph brown's interrupt list helpful;
also I checked out the DOSEMU sources and (of course) plex86's vga.*.

So.. now you guys know what my VGA BIOS is all about.. can you still use
it even though it was made after I reverse engineered my own BIOS? Would
that put legal obligations on Plex86 that are not consistent with LGPL?
I think it's OK with GPL.

Please lemme know. I'm not planning on adding S3 specific things unless
someone's going to use it... because I have no use for it. Windows 95
runs in VGA-only mode. I'm eager to find out how the hell Windows works,
but I need something smarter than what I've got now. I have some ideas,
like keeping tack of where instructions that get executed came from...
that involves using bochs to watch windows... already I can watch MS-DOS
7 boot in BOCHS and it keeps track of what DOS functions get called. Did
you know that if you create a file called JO.SYS on a SYSTEM floppy
disk, and reboot, it will try to boot JO.SYS? In fact Windows 98 does
the same thing; even off of hard disks; provided it is a FAT 12/16 disk
and not FAT 32.

Weird, huh? And there are 3 instructions (taking a total of 10 bytes) in
the boot sector that are put there ON PURPOSE to do that. It first
checks all the slots for JO.SYS and if it's not found, it checks them
for IO.SYS. Wierd! Also later on, when MS-DOS 7 is booting, it actualyl
uses the INT 21 EXEC command to execute IO.SYS, but not before it tries
to do that with JO.SYS. Only if JO.SYS isn't found does it use IO.SYS.

ALso there is a bug I call the 666 bug because Microsoft screwed up the
error message reporting in IO.SYS for Windows 9x, and by chance, the
worst-case scenario is that the user will see precisely 666 bytes of
garbause on the screen, then it will wait for them to press any key, and
then reboot.

Hehe.

Bart Oldeman wrote:
> 
> On Wed, 7 Mar 2001, Chip Salzenberg wrote:
> 
> > Is the Elpin BIOS specialized for use with Plex86, if only in such a
> > minor way as knowing what kinds of pseudo-hardware it's going to find?
> > More to the point, does Plex86 effectively require that the BIOS it
> > uses be specialized in this way?  If so, then Plex86 is actually
> > depending on the specific features of non-free software, and it does
> > belong in contrib.
> >
> > However, if Plex86 does not require any specialization in the BIOS it
> > uses, then Plex86 belongs in Debian's "main".  IMO.
> 
> The Elpin BIOS is a VGA BIOS and cannot be distributed with the rest of
> plex86 in Debian (main). If there is no free VGA BIOS, then it might be
> possible to use the systems own native bios. I don't know how well that
> works: it's chipset dependent and the initialisation routine of the native
> bios often uses additional ports that may confuse plex86, but that might
> not be a problem.
> 
> Something like
> dd if=/dev/mem of=vgabios bs=32768 count=1 skip=24
> 
> For Bochs this is not possible of course (on something different from
> a PC).
> 
> But hey, why not start writing your own vga bios? Dosemu has done most of
> it in 32-bit space (monitor space), but the fonts can be copied straight
> away. It's only a 32k binary (but in assembly that's not negligible,
> sigh).
> 
> Bart

Reply via email to