Running Mac OS X as a QEMU/KVM Guest

Gabriel L. Somlo

Last updated: Sat. Nov. 09, 2013
Feedback to: somlo at cmu dot edu

0. I Just Want It Working, Right Now !

OK, here's what you'll need (or skip to the technical details instead): Once the above components are in place, you'll need a HDD image for your Mac OS X guest:
	cd /home/$(whoami)/OSXGUEST
	qemu-img create -f qcow2 mac_hdd.img 30G
To start your Mac OS X guest in QEMU, use the following command line:
	bin/qemu-system-x86_64 -enable-kvm -m 2048 -cpu core2duo \
	  -usb -device usb-kbd -device usb-mouse \
	  -bios bios-mac.bin -kernel ./chameleon_2.0_boot \
	  -device isa-applesmc,osk="insert-real-64-byte-OSK-string-here" \
	  -acpitable file=./seabios/out/acpi-dsdt.aml \
	  -device ahci,id=ide \
	  -device ide-drive,bus=ide.2,drive=MacHDD \
	  -drive id=MacHDD,if=none,file=./mac_hdd.img \
	  -netdev user,id=hub0port0 -device e1000,netdev=hub0port0,id=eth0 \
	  -monitor stdio
When running the OS X guest for the first time, you'll need to install the operating system to the HDD image, so you'll need to add (and boot from) an install DVD image on the command line.
	  -device ide-drive,bus=ide.0,drive=MacDVD \
	  -drive id=MacDVD,if=none,snapshot=on,file=../DVD/SnowLeopard.10.6.iso
I obtained mine from the original retail SnowLeopard DVD release (version 1.6, a.k.a. 1.6.0), using the following command:
	dd if=/dev/dvd of=../DVD/SnowLeopard.10.6.iso
Another optional command line parameter could be used to start an SMP guest, such as:
	  -smp 8,cores=4
There are still a few remaining issues to be worked out:
Legal Disclaimer: I am not a lawyer, and this is not legal advice. Taking into account that OS X is now officially supported on commercial virtualization solutions such as VMWare Fusion and Parallels, and after a careful reading of Apple's OS X EULA (which states that "[...] you are granted a [...] license to install, use and run one (1) copy of the Apple Software on a single Apple-Branded computer at any one time"), it is my belief that it's OK to run Mac OS X as a QEMU guest, provided the host hardware is a genuine, Apple-manufactured Mac computer, running an arbitrary (e.g. Linux) host OS. This happens to be how I'm using it, but YMMV.

Please read on for a detailed overview of all the issues involved !

1. Intro, Motivation, and Overview

This work started out as my OS Practicum project during the Fall of 2012, where I picked Mac OS X on QEMU/KVM as my topic. I'm a "native" Linux user, but my IT department supports quite a few Mac OS X users, and I decided I could be much faster and more productive if I could access a Mac as a VM guest rather than dual-boot or cold-start an additional machine each time it was needed.

The original work to enable OS X to run under QEMU/KVM was done by Alexander Graf. Additional kernel and userspace patches were contributed by René Rebe. Previously available patches and documentation I reviewed include: Several different components must successfully interact with each other to facilitate running Mac OS X as a QEMU/KVM guest. Each component is listed below, with a link to its dedicated section covering relevant aspects and outstanding issues related to Mac OS X guest support:

2. KVM Kernel Module

KVM is the component located at the lowest level, providing an interface to the virtualization support offered by (among a few others) the x86_64 hardware architecture. Let's begin with a brief list of upstream resources: Two outstanding issues require out-of-tree patching of the KVM module. The first one is known as "ioapic-polarity", and the second one is related to the use of the MONITOR/MWAIT pair of CPU instructions by Mac OS X.

2.1. The "ioapic-polarity" patch

This patch is a misleadingly simple-looking one liner, which removes a single line from virt/kvm/ioapic.c (or x86/ioapic.c in the kvm-kmod version):
-	irq_level ^= entry.fields.polarity;
Without removing this line, a Mac OS X guest hangs during boot with an error message that reads: "still waiting for root device".

According to Alex Graf, this patch was submitted to (and rejected by) mainline KVM several years ago. There seems to be some inconsistency between Mac OS X and the QEMU/SeaBIOS ACPI DSDT about whether PCI APIC lines should be active-high or active-low (active-low being the way things work in practice). The patch ignores the distinction by always issuing an interrupt whenever the line status changes.

Understanding the source of the discrepancy, and fixing the problem (most likely somewhere in SeaBIOS/ACPI and/or Chameleon) is one of the major outstanding issues preventing out-of-the-box Mac OS X guest support in QEMU/KVM.

2.2. MONITOR/MWAIT instruction support

The MONITOR and MWAIT instructions have become a very popular method for modern operating systems to implement Idle Threads in an energy-efficient way. These instructions started shipping on x86_64 chips (Intel and AMD) in the 2006 time frame. According to specs, the OS must check for their availability via CPUID before utilizing them, to avoid encountering an Invalid Opcode exception.

The problem is that, on one hand, KVM does not support MONITOR and MWAIT, issuing Invalid Opcode exceptions to any guest attempting to execute such an instruction. On the other hand, Mac OS X will invoke the instructions from its default idle thread (AppleIntelCPUPowerManagement.kext) indiscriminately, without checking CPUID. My hypothesis is that since any and all Intel-based Mac computers ever shipped came with CPUs that supported MONITOR and MWAIT, OS developers at Apple simply assume the instructions are always present on any hardware configuration they could possibly care to support.

As explained in more detail in the specs and in my Idle Thread slides, MONITOR will "arm" the CPU monitoring hardware to watch for writes to a given memory location; a write to that location will "trigger" the monitoring hardware; and MWAIT will put the CPU core to sleep if the monitoring hardware is armed, until such time that a write, interrupt, or some other event triggers it. If unarmed, MWAIT simply behaves as a NOP.

Architecturally, both MONITOR and MWAIT are equivalent to a NOP instruction, and the monitoring hardware is invisible to the CPU programmer. MWAIT can be seen as a prolonged, low-power NOP instruction whose duration is determined by the above-mentioned "invisible" state in the CPU silicon. Additionally, the CPU programmer must expect spurious wakeups (MWAIT may wake before it's "supposed to"), and therefore use the instruction from within a polling loop.

The remainder of this section discusses a variety of ways in which KVM can offer sufficient support for MONITOR and MWAIT to enable Mac OS X guest execution.
2.2.1. Allow MONITOR/MWAIT to be executed in guest mode.
Currently, KVM configures the physical CPU in a way that causes it to trap out of guest mode back into host mode (a.k.a. perform a VM exit) when one of a list of privileged instructions (e.g. HLT, but also MONITOR and MWAIT) is encountered. One of the early patches I encountered simply removed MONITOR and MWAIT from that list, preventing a VM exit upon their encounter during guest (a.k.a. VMX-non-root or L>0) mode.

According to the
spec (see V3, S25-3, pp25-8), under certain conditions (which happen to be met by the OS X idle thread), guest-mode MWAIT will always default to being treated as a NOP, never entering a low-power sleep state. This causes each guest VCPU to always utilize 100% of a host core, regardless of the actual level of guest activity.
2.2.2. Emulate MONITOR/MWAIT as NOP
As mentioned above, KVM currently requests that, among other instructions, MONITOR and MWAIT generate a VM exit and be handled in host (rather than guest) mode. The current handler for both instructions generates an Invalid Opcode exception, a behavior consistent with the non-support for the instructions advertised via CPUID.

My current stable patch against KVM replaces the handler for MONITOR and MWAIT with one that emulates the NOP instruction (i.e., skips the current MONITOR or MWAIT and re-enters VM guest mode execution from the immediately following instruction). As before, these are short, non-power-saving NOP instructions, and therefore each VCPU will utilize 100% of the available cycles of a physical core on the host.

As a workaround, it is possible to force Mac OS X to revert to a HLT-based idle thread by removing the default MONITOR/MWAIT one:
	sudo rm /System/Library/Extensions/AppleIntelCPUPowerManagement.kext
This reduces host core utilization to single digits during guest idle times, since the guest VCPUs are removed from scheduling and execution on the host while halted.

Due to its simplicity and relative cleanliness, this combined approach may be a viable long term solution: NOP-based MONITOR/MWAIT emulation will allow booting Mac OS X from factory-default install media. Once installed, the guest may be "optimized" for power consumption and host CPU utilization by forcing it to fall back to a HLT-based idle thread.
2.2.3. Emulate MWAIT as HLT
Assuming the requirement to run a completely unmodified OS X guest install, we must support the default MONITOR/MWAIT idle thread in production, and attempt to alleviate host CPU utilization without the option of falling back to the HLT-based version. An interesting observation is that, on single-processor systems, MWAIT behaves very much like HLT: there is no other (V)CPU to trigger the monitoring hardware, and therefore MWAIT will only wake when a hardware interrupt is asserted.

If we attempted to emulate MWAIT as (something similar to) HLT, while continuing to treat MONITOR as a NOP, we might be able to reduce host CPU utilization at the price of having the MWAIT-based idle thread be somewhat "sluggish" (waking up "late", on hardware interrupt, as opposed to "on time" when another VCPU writes to the monitored memory location). This may have a negative impact on e.g. the real-time performance of the OS X guest, but considering we're already running under virtualization,
you can't lose what you ain't never had :)

We'd have to pay attention to the fact that the OS X idle thread runs with interrupts disabled (RFLAGS.IF=0), but sets %ecx=1 to make MWAIT wake on interrupt regardless. This experimental patch implements MWAIT as an always-interruptible (regardless of RFLAGS.IF) version of HLT. The patch works well enough on a single-processor guest, reducing host CPU utilization during guest idle to about 15%. However, when booting on an SMP guest, OS X crashes with an "HPET not found" panic, which could indicate any number of problems: These issues are currently under investigation, so please stay tuned...
2.2.4. Emulate the monitoring hardware
Although the spec strongly warns against assuming any connection between the size of the memory chunk being monitored and the size of a cache line, it is obvious that MONITOR and MWAIT are implemented on top of the processor's cache coherence protocol (e.g., MESI). A plausible approach could work like this: A relatively straightforward way to emulate MONITOR and MWAIT in KVM would be to utilize the virtual MMU module to write-protect MONITOR-ed memory areas, and handle the subsequent write faults (by emulating the actual guest write from within the host, and updating the state of the emulated monitoring hardware accordingly). This approach has one major caveat: memory monitoring necessarily happens at page-level granularity, which is typically significantly larger than the the extent of a (few) cache line(s) typically used on real hardware. It is true that the exact extent of the monitored memory area is advertised via CPUID, but OS X is already known to have a poor track record of honoring CPUID.

This new experimental patch implements MONITOR/MWAIT by emulating the monitoring hardware on top of the KVM MMU, as described above. As an optimization step (to avoid a TLB shootdown each time the write-protection on a monitored page is switched on or off), the patch is implemented as folows: Similarly to the MWAIT as HLT method, this patch only works reliably on single-VCPU guests. The patch sometimes works with '-smp 2,cores=2' (about 30% of the time) as shown in this screenshot. Some other times, the emulated disk controller (AHCI) hangs. Other times, as well as with any attempt at SMP higher than 2, we get the dreaded HPET panic. I'm currently looking for ways to first explain, then debug this behavior.

3. QEMU

QEMU is a multi-architecture emulator running in user-space. For certain architectures (such as x86_64), QEMU is able to take advantage of hardware virtualization features offered through e.g. KVM, which allow it to run guests at near-native performance levels. Here is roughly how QEMU and KVM work together to implement a guest VM: A quick list of QEMU upstream resources might include: There are three relevant topics regarding support for Mac OS X guests: QEMU's recent inclusion of support for the Q35/ICH9 based architecture; emulation of Apple's System Management Controller (a.k.a. AppleSMC); and, finally, a few issues related to QEMU's emulation of the e1000 network controller, one of which is currently handled by this out-of-tree patch.

3.1. The Q35/ICH9 architecture

Support for the Q35 architecture was recently (Dec. 2012) merged into QEMU mainline. Q35 replaces the old I440FX with Intel's more modern ICH9 chipset, which also happens to be used on most Intel-based Apple hardware. Among other hardware, ICH9 includes an integrated AHCI disk controller, which had to be added explicitly on the pre-Q35 QEMU command line:
	bin/qemu-system-x86_64 -enable-kvm -m 2048 -cpu core2duo \
	  -usb -device usb-kbd -device usb-mouse \
	  -bios bios-mac.bin -kernel ./chameleon_2.0_boot \
	  -device isa-applesmc,osk="insert-real-64-byte-OSK-string-here" \
	  -M q35 -acpitable file=./seabios/out/q35-acpi-dsdt.aml \
	  -device ide-drive,bus=ide.2,drive=MacHDD \
	  -drive id=MacHDD,if=none,file=./mac_hdd.img \
	  -netdev user,id=hub0port0 -device e1000,netdev=hub0port0,id=eth0 \
	  -monitor stdio
As Q35 is slated to become the new default "machine type" in QEMU in the near future, the bulk of the effort (development, debugging, and testing) to get Mac OS X supported under QEMU will be focused on this platform.

While the Q35 command line boots an up-to-date SnowLeopard (10.6.8 or later) without problems, it hangs (most likely due to some USB/uhci/ehci related disagreements) on earlier 10.8.* versions, which unfortunately includes the retail install image. Recent combinations of QEMU+SeaBIOS sometimes manage to work with the install disk, but only on an SMP guest. For now, installing a new OS X guest from scratch requires the pre-Q35 command line.

3.2. The AppleSMC emulator

The AppleSMC (or System Management Controller) is a chip specific to Intel-based computers manufactured by Apple. Its main purpose is to control (and report on) fan speeds, temperature sensors, screen and keyboard light intensity levels, and miscellaneous other power management features.

From the point of view of the operating system driver, interaction with the SMC happens via port-based I/O: The name of a 4-character key is written to a control port, and the key's numeric or ASCII value is then read from (or written to) a data port. Keys typically represent fan speeds, light intensity levels, or temperatures.

There are currently three outstanding issues with QEMU's AppleSMC emulation which could improve Mac OS X guest support, outlined below.
3.2.1. Automatic OSK "pass-through" on Apple hardware
The AppleSMC is also used to store a 64-byte ASCII string copyrighted by Apple, spread across two 32-byte key values, named OSK0 and OSK1. This string is used by Mac OS X to determine whether it's being booted on genuine Apple hardware. QEMU does not set up AppleSMC emulation by default (since only OS X guests require it at this time). To set it up, the following QEMU command line snippet is required:
	-device isa-applesmc,osk="insert-real-64-byte-OSK-string-here"
The user is required to supply the correct value of the 64-byte OSK string as an argument, and responsible for honoring Apple's OS X EULA (which states that "[...] you are granted a [...] license to instal, use and run one (1) copy of the Apple Software on a single Apple-Branded computer at any one time").

I wrote a small C program, SmcDumpHw.c, which can be used to read various SMC key values (including OSK0 and OSK1) from an Intel Mac running Linux. However, a significant improvement in usability and ease of compliance with the OS X EULA could be accomplished by allowing QEMU's AppleSMC emulator to automatically acquire the OSK strings from the underlying (Apple) host hardware.

Currently, the drivers/hwmon/applesmc.c Linux driver populates a Sysfs directory (/sys/devices/platform/applesmc.768/) which offers access to most SMC key values. Unfortunately, that does not include OSK0 and OSK1. I submitted this patch against the applesmc.c Linux driver, but encountered two main objections (also see the various other replies in the referenced thread): I'm planning to follow up with the Linux maintainer of applesmc.c again in the near future to reiterate these points, but in the mean time I could really use some advice and feedback from anyone with successful patch submission experience to the Linux kernel :)
3.2.2. OS X fails to write a key value to the emulated SMC
During boot, Mac OS X 10.6 (Snow Leopard, the only version currently working under QEMU) logs a few non-fatal SMC-related errors:
	SMC::smcGetVersWithSMC ERROR: smcReadKey REV failed (0xff)
	SMC::smcInitHelper ERROR: smcPublishVersion failed (0xff)
	SMC::smcInitHelper ERROR: smcPublishShutdownCause failed (0xff)
	SMC::smcPublisVersion ERROR: smcGetVers for SMC 0 failed (0xff)
	SMC::smcNotificationPublishedHandler ERROR: smcWriteKey NTOK failed (0xff), will not receive interrupts
It appears that emulating a few extra SMC keys, as well as allowing the OS X guest to write (as opposed to just read) some of the supported keys might make these errors go away.
3.2.3. Support for SeaBIOS ACPI autodection of SMC via fw_cfg
Since AppleSMC emulation is only included upon explicit request via the QEMU command line, we run into the issue of how to support the device in the ACPI firmware, as described below. An important QEMU-related ToDo item is to add support for reporting on the SMC's presence to the QEMU "fw_cfg" device, which will facilitate the writing of ACPI auto-detection methods in SeaBIOS.

3.3. The e1000 virtual network card

By default, QEMU uses the emulated e1000 network controller when starting a new guest, unless a different model is explicitly requested. Older versions of QEMU defaulted to the rtl8139 controller. OS X 10.6 (Snow Leopard) can use either model, but as a QEMU guest was unable to recognize the e1000 on older versions of QEMU, and is unable to recognize the rtl8139 on current QEMU git master. Since the e1000 is a more modern controller (as well as the new default), I decided not to spend any time figuring out why the rtl8139 isn't recognized, and get e1000 to work properly instead.

An already committed patch fixes the failure of OS X to configure the default MAC address (reporting "00:00:00:00:00:00" instead). OS X most likely expects the Apple EFI BIOS to initialize the network controller to the point where its capable of listening for packets targeted at its own factory-default MAC address. Most other operating systems will take care of all this from within their respective drivers, but for now OS X needs QEMU to take care of this part on its behalf.

Even once OS X can detect its e1000 network card with the correct MAC address, we are left with a failure to negotiate a virtual Ethernet "link" once the guest completes its boot sequence. While this will most likely require an additional patch against QEMU's e1000 emulator, the current workaround involves manually "disconnecting" and "re-connecting" the virtual ethernet "link" from the QEMU monitor interface. The part of the QEMU OS X guest command line which starts the monitor is:
	-monitor stdio
From there, we can list the guest VM device tree by issuing the "info qtree" command, and look for the default Ethernet card:
	(qemu) info qtree
	...
	      dev: e1000, id ""
	        mac = 52:54:00:12:34:56
	        vlan = 0
	        netdev = hub0port0
	...
We need to assign a name to the e1000 device (by assigning a value to its id field), to facilitate subsequently issuing commands against it from the QEMU monitor interface. We do that via the following command line snippet:
	-netdev user,id=hub0port0 \
	-device e1000,netdev=hub0port0,id=eth0
The new output of "info qtree" shows that the device's ID field is now set to "eth0":
	(qemu) info qtree
	...
	      dev: e1000, id "eth0"
	        mac = 52:54:00:12:34:56
	        vlan = 
	        netdev = hub0port0
	...
We can now bounce the PHY (or "ethernet link") by issuing the following pair of commands from the QEMU monitor interface:
	(qemu) set_link eth0 off
	(qemu) set_link eth0 on
This enables the OS X network driver to detect an ethernet "link", allowing us to begin doing useful work from within the guest.

3.4. Boot OS X on QEMU without KVM hardware assistance

This part isn't truly necessary for supporting production OS X guests expected to do real work. It would however be interesting for debugging purposes to be able to run OS X in fully emulated mode, without any KVM hardware assistance. More digging might reveal further interesting information...

4. SeaBIOS

SeaBIOS is the default BIOS for QEMU/KVM. The QEMU source tree includes a relatively up-to-date snapshot of SeaBIOS (in pre-built, binary form). However, supporting Mac OS X currently requires patching SeaBIOS, and therefore we build a separate binary (bios-mac.bin) from current git master, and use it to start the OS X guest instead. Upstream resources include: The current patch against SeaBIOS is split along two main directions: ACPI DSDT fixes for the HPET and AppleSMC chips, and Mac-specific updates to the SMBIOS module.

4.1. A brief intro to ACPI BIOS hackery

ACPI (Advanced Configuration and Power Interface) is an open standard for how modern operating systems should implement device configuration and power management. Its specification defines (among many other things) a set of tables which provide an interface between compliant operating systems and system firmware (such as the DSDT), and a language (ASL) in which so-called "device nodes" are defined in these tables. A controversial feature of ACPI is the requirement that the operating system execute the (externally provided, from its point of view) bytecode compiled into the BIOS from ASL source with full privileges.

The DSDT (Differentiated System Description Table) supplies critical information about the various hardware devices which comprise the base system. We will focus on the entries (or "nodes") of two such devices: the AppleSMC and the HPET. ASL source code for the DSDT of a system running Linux can be extracted using the following steps:
	acpidump > acpidump.out
	acpixtract acpidump.out
	iasl -d DSDT.dat
The last step generates a file named DSDT.dsl, which contains ASL source code. Let's examine the entry corresponding to the SMC:
	Device (SMC) {
	    Name (_HID, EisaId ("APP0001"))
	    Name (_STA, 0x0B)
	    Name (_CRS, ResourceTemplate () {
		IO (Decode16, 0x0300, 0x0300, 0x01, 0x20)
		IRQNoFlags () {6}
	    })
	}
Section 6 of the ACPI spec explains the meaning of each object: Objects are often specified as constants (e.g., our SMC._STA() always returns a hardcoded value of 0xB, and no computation is performed to actually probe the device). In that case they may be declared as "Named Objects", as shown in the example above. Should we require an actual computation, we would have to declare the relevant object as a "Method". For example, the expression "Name (_STA, 0x0B)" is equivalent to:
	Method (_STA, 0) {
	    Return (0x0B)
	}
This latter form enables the operating system to find out at boot time whether or not a functional SMC device is included with the underlying (virtual) machine.

4.1.1. Mac OS X and the SMC DSDT node
My current SeaBIOS patch adds an SMC node to the DSDT with a hardcoded constant _STA value of 0x0B (very similar to the one found on real hardware). This makes it unacceptable for upstream SeaBIOS, because most often QEMU will be started without the "-device isa-applesmc" command line option, and the resulting guest VM will therefore lack a present/enabled/functional SMC. Either QEMU would have to dynamically build a DSDT based on its command line options and then incorporate it into SeaBIOS before starting the guest VM, or the SMC._STA() method would have to somehow probe for the presence of the SMC, and return 0x0B only if the SMC is found (and 0x00 otherwise). After some discussion on the SeaBIOS mailing list, it appears that the preferable solution might be a permanent SMC node in the DSDT, with auto-detection logic built into the _STA() method.

What would such a SMC._STA() look like? A first-pass, naive implementation could be written like this:
	/* 32-byte operational region, starting at SMC base address */
	OperationRegion(SMIO, SystemIO, 0x0300, 0x20)

	/* SMC data and command ports */
	Field(SMIO, ByteAcc, Lock, Preserve) {
	    DATP, 8,
	    Offset (0x04),
	    CMDP, 8,
	}

	Method (_STA, 0) {
	    Store (DATP, Local0)	/* read from data port */
	    Store (CMDP, Local1)	/* read from command port */

	    /* DATP and CMDP should NOT be 0xFF if SMC present !!! */
	    If (LOr (LEqual(Local0, 0xFF), LEqual(Local1, 0xFF))) {
		Return (0x0)
	    }

	    /* assume SMC is available */
	    Return (0x0B)
	}
and rely on the fact that reading from unmapped I/O ports returns a value of 0xFF. If the value read is different, we may assume that a real device is present at the respective I/O addresses. The downside of this approach is that we have no guarantee it's an actual SMC device and not something else that's mapped at those I/O ports, in which case we may cause harm by changing the state of an unknown device.

Another suggestion was to issue an actual SMC command and check for the expected response:
	OperationRegion(SMIO, SystemIO, 0x0300, 0x20)
	Field(SMIO, ByteAcc, Lock, Preserve) {
	    Offset (0x04),
	    CMDP, 8,
	}
	Method (_STA, 0) {
	    Store (0x10, CMDP)		/* APPLESMC_READ_CMD */
	    Store (CMDP, Local0)
	    If (LEqual(Local0, 0x0C)) {
		Return (0x0B)
	    }
	    Return (0x00)
	}
Issuing a "Read Command" (0x10) to the SMC should cause its command port to return 0x0C when read, which should tell us we're dealing with a bona fide SMC and not some other chip. Unfortunately, 0x0C means the SMC is now waiting for the name of a key to be written to its data port, a state that's very different from the default initial state of the chip, a difference that will subsequently lead to the failure of the booting guest OS to interact with the SMC. Even worse, if the mapped chip is not an SMC, we're now writing to it instead of just reading, which could cause at least as much damage as in the previous example.

The current plan is to probe the I/O ports of the QEMU "fw_cfg" device from SMC_STA() instead of the SMC's own I/O ports. We are guaranteed to have a fw_cfg device always present at I/O control port 0x510 and data port 0x511 on any QEMU guest VM. We first need to make arrangements to have the presence or absence of the emulated AppleSMC available via fw_cfg.
4.1.2. Mac OS X and the HPET DSDT node
I have submitted an HPET DSDT patch to enable QEMU+SeaBIOS to boot Mac OS X guests. The line:
	    IRQNoFlags() {2, 8}
in the _CRS method is needed for booting an SMP (multi-VCPU) OS X guest. However, it seems to cause trouble for Windows XP, and has since been partially reverted. A solution that addresses all concerns could be to conditionally add the IRQNoFlags line to _CRS only when running an OS X guest, which we may assume is strongly correlated to the presence of an SMC node (or to the success of the SMC._STA() method). One example bases the conditional inclusion of the IRQ resource on the presence of the SMC node:
	Name(RES_MIO, ResourceTemplate() {	/* MMIO resource */
	    Memory32Fixed(ReadOnly, 0xFED00000, 0x00000400)
	})
	Name(RES_IRQ, ResourceTemplate() {	/* IRQ resource */
	    IRQNoFlags() {2, 8}
	})
	Method(_CRS, 0) {
	    If (CondRefOf(\_SB.PCI0.ISA.SMC, Local0)) {
		/* AppleSMC present, include IRQ resource */
		ConcatenateResTemplate(RES_MIO, RES_IRQ, Local1)
		Return (Local1)
	    } else {
		/* AppleSMC not present, omit IRQ resource */
		Return (RES_MIO)
	    }
	}
Another example uses the result of the SMC._STA() method, assuming a SMC node is always present in the DSDT:
	Name(RES_MIO, ResourceTemplate() {	/* MMIO resource */
	    Memory32Fixed(ReadOnly, 0xFED00000, 0x00000400)
	})
	Name(RES_IRQ, ResourceTemplate() {	/* IRQ resource */
	    IRQNoFlags() {2, 8}
	})
	Method(_CRS, 0) {
	    Store(\_SB.PCI0.ISA.SMC._STA(), Local0)
	    If (LEqual(Local0, 0x0B)) {
		/* AppleSMC present, include IRQ resource */
		ConcatenateResTemplate(RES_MIO, RES_IRQ, Local1)
		Return (Local1)
	    } else {
		/* AppleSMC not present, omit IRQ resource */
		Return (RES_MIO)
	    }
	}
I plan to submit this latter version once I have a working SMC status auto-detect method as described above.

4.2. SMBIOS fixes

The second part of the current SeaBIOS patch was written by Alex Graf and/or René Rebe, and adds Mac-specific data structures to the SMBIOS component of SeaBIOS. The main effect of this patch is to enable "About This Mac" functionality from the OS X system menu, which would otherwise result in Finder crashing and being restarted.

I don't yet know how I would go about upstreaming this particular bit into SeaBIOS, but suggestions are welcome !

5. Chameleon

Chameleon is a Darwin/XNU boot loader based on Apple's boot-132. It is currently used to override some of the underlying BIOS settings, and generally bridge the gap between the existing BIOS and the EFI BIOS of genuine Apple Mac computers expected by OS X during boot. Project resources include: The project is meant to be built under OS X itself, and also depends on Xcode. Once these prerequisites are met, simply running 'make' in the appropriate SVN subdirectory will build the bootloader. Luckily, the SnowLeopard install DVD also includes a copy of Xcode, so I used my OS X guest VM to build Chameleon 2.0 from the SVN repository. To initially boot the VM, you may temporarily use my precompiled Chameleon binary. After the Chameleon source build completes, find the resulting "boot" binary and copy it to our working directory as e.g. "chameleon_2.0_boot".

5.1. Chameleon Build Issues

Current (at the time of this writing, 2168) SVN trunk (and also the branch tagged 2.1) fails to build on SnowLeopard+Xcode. When attempting to link boot.sys, we get this error:
	[LD] boot.sys
ld: warning: -segaddr __INIT not page aligned, rounding down
ld: warning: -segaddr __TEXT not page aligned, rounding down
ld: warning: -segaddr __DATA not page aligned, rounding down
ld: segments overlap: __DATA (0x0005DFFE + 0x0000F000) and __LINKEDIT (0x0005E000 + 0x00001000)
It may be possible that later versions of OS X and/or Xcode are required to properly build the latest Chameleon versions.

5.2. Supporting Mac OS X versions beyond 10.7 (*Lion)

When using pre-2.0 versions of Chameleon, attempting to boot (Mountain)Lion from unmodified Apple boot media results in a crash behaving a lot like a triple-fault. With Chameleon 2.0, (Mountain)Lion no longer triple-faults on startup, but instead generates the following kernel panic during boot:
	Unable to find driver for this platform:
	"\ACPI\".\n"@/SourceCache/xnu/xnu-1699.22.73/iokit/Kernel/IOPlatformExpert.cpp:104
In all likelihood, solving this problem may also involve further SeaBIOS fixes, but successfully building and testing with the latest Chameleon SVN trunk would be a good start.

I have received a few reports of MountainLion running as a QEMU guest, but usually also involving a few Hackintosh-inspired steps that are not 100% clear and reproducible to me. I'd be really interested in reports of working (Mountain)Lion QEMU guests, but with (as many of) the following details (as humanly possible):

6. Conclusion and Future Work

My ultimate goal is to make whatever changes are needed to KVM/QEMU/SeaBIOS/Chameleon to allow installing from unmodified, vanilla Apple install images, and to run the guest with no requirement to perform any post-install "surgery" on the guest HDD image. If absolutely necessary, a small number of well documented mods may be tolerated. As I mentioned elsewhere, I'm not looking to run a Hackintosh, but rather a well-supported OS X guest under QEMU/KVM on an Apple-made machine natively running Linux.

Currently, I'm planning to work on the issues outlined above, in the following order of priority: That's a fair amount of work, so ideas, suggestions, or, should you be interested, actual help hacking on this stuff would be most welcome and appreciated!

For the (long-term) future, another interesting idea I saw vehiculated was to completely replace the Chameleon+SeaBIOS tandem with a (U)EFI compliant BIOS such as e.g. TianoCore, and try to get it to boot every OS (OS X included) natively.