Running Mac OS X as a QEMU/KVM Guest

Gabriel L. Somlo

See the old version of this page here.

FINAL UPDATE (2018-10-21):
I no longer have the cycles to work on this project. At this point QEMU and KVM are mostly capable of supporting OS X (up to Sierra), and the largest portion of the effort still required lies with edk2/ovmf (start with my fork on github as indicated below, and go from there).
Additionally, since Apple machines have become increasingly locked down and end-user unfriendly, I can't continue considering them for any upcoming hardware refresh (which is too bad, they used to make almost perfect Linux machines for the last 20 years!).

NOTE: Installer .iso images prepared based on Sierra 10.12.4 or later will hang during boot. However, guest images installed with 10.12.3 or earlier can successfully be upgraded, assuming the applesmc fix mentioned above is applied. The cause for this is as of yet unknown (to me, at least).

1. Prerequisites

You will need the following: I currently use Fedora 26. Anything close to it in terms of "freshness" should likely do just fine.

To build the patched OVMF firmware blob, follow these instructions:
    git clone https://github.com/gsomlo/edk2.git
    cd edk2
    git checkout gls-miscopt
    make -C BaseTools
    . edksetup.sh BaseTools
    build -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc
    cp $(find ./Build/ -name OVMF.fd) ~/
The result of this process is a firmware blob named OVMF.fd, which will be copied to your home directory by the last command shown above. A binary OVMF blob built by applying my patches on top of the current edk2 master branch (as indicated by the abbreviated commit ID in the file name) is available to help speed things up, but you're strongly encouraged to build your own :)

2. Creating an OS X boot DVD iso image

SnowLeopard (10.6) was the last OS X version released in DVD format. Starting with Lion (10.7), an install DVD (.iso) image may be generated on an OS X machine by following the steps below (Thanks Dick Marinus for pointing out the Yosemite-specific updates!):
    # As of Yosemite, this really only works if executed as root,
    # so let's start with that:
    sudo -s

    # Mount the installer image:
    hdiutil attach /Applications/Install\ OS\ X\ Yosemite.app/Contents/SharedSupport/InstallESD.dmg -noverify -nobrowse -mountpoint /Volumes/install_app

    # Convert the boot image to a sparse bundle:
    hdiutil convert /Volumes/install_app/BaseSystem.dmg -format UDSP -o /tmp/Yosemite

    # Increase the sparse bundle capacity for packages, kernel, etc.:
    hdiutil resize -size 8g /tmp/Yosemite.sparseimage

    # Mount the sparse bundle target for further processing:
    hdiutil attach /tmp/Yosemite.sparseimage -noverify -nobrowse -mountpoint /Volumes/install_build

    # Remove Package link and replace with actual files:
    rm /Volumes/install_build/System/Installation/Packages
    cp -rp /Volumes/install_app/Packages /Volumes/install_build/System/Installation/

    # NEW: As of Yosemite, there are additional installer dependencies:
    cp -rp /Volumes/install_app/BaseSystem* /Volumes/install_build/

    # NEW: As of Yosemite, we also need a kernel image!
    # Assuming we're executing these steps on a Yosemite machine with
    # a version EXACTLY matching that of the installer we're preparing:
    cp -rp /System/Library/Kernels /Volumes/install_build/System/Library/
    # NOTE: If the running OS X version is not identical to that of
    #       the installer being prepared, one may copy the
    #       necessary files (/System/Library/Kernels/*) from the
    #       /Volumes/install_app/Packages/Essentials.pkg package,
    #       using third party software (e.g. Pacifist -- WARNING:
    #       shareware, not free/open source software, your ideological
    #       purity may vary).

    # Unmount both the installer image and the target sparse bundle:
    hdiutil detach /Volumes/install_app
    hdiutil detach /Volumes/install_build

    # Resize the partition in the sparse bundle to remove any free space:
    hdiutil resize -size $(hdiutil resize -limits /tmp/Yosemite.sparseimage | tail -n 1 | awk '{ print $1 }')b /tmp/Yosemite.sparseimage

    # Convert the sparse bundle to ISO/CD master:
    hdiutil convert /tmp/Yosemite.sparseimage -format UDTO -o /tmp/Yosemite

    # Remove the sparse bundle:
    rm /tmp/Yosemite.sparseimage

    # Rename the ISO and move it to the desktop:
    mv /tmp/Yosemite.cdr ~/Desktop/Yosemite.iso

3. Starting the OS X Guest

First, create an empty hard drive image:
    qemu-img create -f qcow2 mac_hdd.img 64G
Using the following command line, install OS X from the boot media created earlier (Thanks Jim Burns for the Penryn hint, which is needed instead of core2duo as of Sierra):
    bin/qemu-system-x86_64 -machine q35,accel=kvm -bios ~/OVMF.fd -m 4096 \
      -cpu Penryn -smp 4,cores=2 \
      -usb -device usb-kbd -device usb-tablet \
      -device isa-applesmc,osk="insert-real-64-char-OSK-here" \
      -netdev user,id=usr0 -device e1000-82545em,netdev=usr0,id=vnet0 \
      -device ide-drive,bus=ide.0,drive=MacDVD \
      -drive id=MacDVD,if=none,snapshot=on,file=~/DVD/Sierra.10.12.1.iso \
      -device ide-drive,bus=ide.2,drive=MacHDD \
      -drive id=MacHDD,if=none,file=~/mac_hdd.img \
      -monitor stdio
In addition to the OVMF.fd firmware blob, the DVD image, and a blank hard drive image, you'll need to provide the value of OSK0 and OSK1, as a single concatenated 64-character string. If you own a Mac and run Linux on it natively (the license-compliant use case for the application of these instructions), you can retrieve them by compiling and running
SmcDumpKey.c.

Finally, to start your freshly installed guest, run:
    bin/qemu-system-x86_64 -machine q35,accel=kvm -bios ~/OVMF.fd -m 4096 \
      -cpu Penryn -smp 4,cores=2 \
      -usb -device usb-kbd -device usb-tablet \
      -device isa-applesmc,osk="insert-real-64-char-OSK-here" \
      -netdev user,id=usr0 -device e1000-82545em,netdev=usr0,id=vnet0 \
      -device ide-drive,bus=ide.2,drive=MacHDD \
      -drive id=MacHDD,if=none,file=~/mac_hdd.img \
      -monitor stdio
NOTE: If using qemu ≤ 2.8, substitute "-device usb-mouse" instead of "-device usb-tablet". A patch to make the latter work with OS X (thanks to Phil Dennis-Jordan) only became available starting with version 2.9.0.

4. Is This Legal?

Let me start with the obligatory disclaimer: I am not a lawyer, and this is not legal advice!

We know that OS X is supported on commercial virtualization solutions such as
VMWare Fusion and Parallels. Reading through Apple's 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 appears everything is OK as long as the underlying hardware is made by Apple. What if the hypervisor OS is different than OS X? (both Fusion and Parallels both use OS X as the hypervisor OS). Well, it appears VMWare ESXi allows running OS X guests (presumably only if the hardware is, once again, manufactured by Apple). This is clearly an example of OS X running as guest on top of a non-OS X hypervisor, on top of Apple-manufactured hardware.

So, it is my belief that, as long as I'm running a Linux/KVM hypervisor on a genuine Mac computer (which I've personally been doing exclusively since cca. 2006, btw), the license does not forbid me from running OS X as a VM guest on top of it.

In terms of advice, all I can say is: Check with the legal and/or moral authorities in your local jurisdiction before trying this at home! :)

5. Future Work

A few things still need work: