Subject: Re: MacOnLinux
To: Emmanuel Dreyfus , <port-macppc@netbsd.org>
From: Benjamin Herrenschmidt <benh@mipsys.com>
List: port-macppc
Date: 03/13/2001 15:52:36
On Tue, Mar 13, 2001, Emmanuel Dreyfus <p99dreyf@criens.u-psud.fr> wrote:

>Hello Ben, happy to see you here :o)
>Could you explain in greater details how it works? What do you mean by
>patching exception vectors? I assume that you must check on exception if
>it was caused by a Linux app or a MacOS app (how do you recognize it?). If
>it's MacOS, then you have a special exception handler?
>
>And about the kernel module: its job is to handle all the kernel side 
>translation between MacOS and Linux. Do you think it would be possible to
>make the sources cross-platform (Linux/NetBSD), or do you think it would be
>easier to reimplment it from scratch?
>
>Last question: is there any userland program for MOL?

Well, I don't know MOL as well as its author, but I can try to answer the
best I can.

So basically, the entire MacOS runs in one process. This process, at a given
point in time, can be running MacOS code, or Linux code (the userland side of
the emulator).

Basically, when the MOL process is running MacOS code, the kernel hooks take
complete control of the MMU setup for this process and catch any privilege
violation. This way, MacOS "thinks" it has full access to the CPU in
priviledged
mode, while in fact, the MMU is completely emulated by the kernel module. The
virtual memory allocated to the MOL process is seen as physical memory by
MacOS, and the "linux side" can register various "IO ranges" (ranges of
emulated
physical addresses).

Any access to such an emulated physical address is trapped by the kernel
module
and control is returned to the linux-side of the MOL process. This side can
then "emulate" the access by providing pseudo-hardware devices. It can also
trigger interrupts.

There's also a layer allowing more direct function calls from the MacOS side
to the Linux side via the "sc" instruction which is trapped by the kernel
module
as well (what we call the OSI calls).

So basically, when you run MOL, you launch a linux userland process. This
process
installs the kernel module and use an additional system call provided by this
module to register various emulated HW devices (mostly the interrupt
controller,
Cuda, the PCI host bridge, and a few IOs). 

Then, the linux side loads the MacOS ROM image ELF and starts the emulation by
running a pseudo OpenFirmware implementation that itself runs the MacOS
ROM image.
This pseudo-OF will provide MacOS with a "cooked" device tree that looks a lot
like a B&W G3, but with additional nodes for the emulated graphic card,
network
adapter, block driver, etc... This device tree also contains MacOS
drivers that are
loaded by MacOS ROM image and that use the MacOS->Linux calls to directly
bridge
to the linux-side "drivers". This avoids the cost of HW registers
emulation and
provide an overall perf. implementation over pure emulation. 

Most exceptions caused by the MacOS process are handled (and emulated) by the
kernel module (everything related to MMU for example). Some are however passed
to the linux side and handled there (all IO emulation, PVR emulation, and
a few
other things).

The kernel module is not so much dependant on the linux kernel I guess.
It's low
level asm would need to be modified to adapt to the different low level
exception
vectors used by BSD, and some hooks into kernel-specific routines (like
flush_tlb
etc...) would need to be changed as well. Most of these are related to
maintaining
the special MMU environement and doing the software MMU emulation.

Ben.