Virtualization powers a lot of infrastructure today, and there have been countless advances made in this field during the last few years. CPUs support more and more advanced hypervisor scenarios, while operating systems gain better and better native virtualization capabilities. Today, even macOS is virtualizable to a significant degree using free, open source tools.
In this post, as well as parts 2 and 3, I'll be focusing on using VirtualBox as the VM host, because it is open source, cross-platform, and it generally works well for this purpose. There are ways to get VMware and QEMU/KVM to host macOS; if you're already in one of those ecosystems, you should be able to find an online guide to help. I'm unaware of any successful attempts at getting Hyper-V to host it, but it could conceivably be done.
The only reason why I decided to attempt virtualizing macOS is because it sounded like an interesting challenge. I have no particular desire to use that operating system, but finding a way to get it working is intriguing to me.
The theory and the terminology
If you're new to the hackintosh scene, you might feel a bit overwhelmed with jargon: DSDT, Clover, kext, Chameleon, SMC, and so forth. Let's start with macOS hardware requirements and go from there. Disclaimer: I can't guarantee the accuracy of the information provided here. This is just my attempt to reconcile the various pieces of info floating around on the web. If something is incorrect, please let me know, and I'll fix it.
Over the years Apple has released quite a few devices that run modern versions of macOS. They all have a couple of things in common: they run on Intel CPUs, and they have specialized hardware to differentiate a Mac from a regular Intel-based machine.
This brings us to the first term: SMC (System Management Controller). The SMC has multiple functions, including controlling LEDs and power management, but for our purposes it only has one interesting function: identifying the hardware that it's running on as a genuine Mac. macOS checks the SMC for a specific string upon booting up, and if the string is missing or corrupted, it will crash with a kernel panic.
This string check is done using an aptly-named kext (kernel extension) called
Dont_Steal_Mac_OS_X. A kernel extension is effectively a dynamically loadable kernel module - code running with very high privileges inside kernel space. There are kexts that function as hardware drivers, for example.
Macs have other common hardware found in many non-Mac machines, such as audio cards, graphics cards, wireless NICs, and so on. Since Apple only has to support a limited number of these devices, it can sometimes be a challenge to get certain functionality working on unsupported hardware. Custom kexts are often the solution.
In order to determine what hardware is present, macOS enlists the help of Intel's EFI (Extensible Firmware Interface), a modern replacement for the venerable BIOS (Basic Input/Output System) firmware, which dates back to the 1970s. In addition to allowing macOS to boot, EFI contains (or allows access to) a lot of metadata in various tables that macOS uses to look up what hardware it needs to initialize. One of these sets of tables is the SMBIOS (System Management BIOS). It contains information about the currently running firmware, as well as metadata about the motherboard and certain peripherals that are attached to it. For example, macOS uses SMBIOS information to determine how much RAM the computer has and which RAM slot(s) are occupied.
EFI also allows access to various parts of ACPI (Advanced Configuration and Power Interface), which has more information about the computer. Part of ACPI is the DSDT (Differentiated System Description Table), which contains system metadata as well as executable code to allow for correct functionality of the operating system, especially when it comes to things like power management.
On a real Mac, the EFI, SMBIOS, ACPI tables, and various other firmware components are all tuned for best compatibility with macOS. On regular machines, they tend to be tuned for compatibility with Windows, or sometimes not tuned at all, or even tuned incorrectly. In order to solve the various issues created by these incompatibilities, a custom bootloader can be used to tweak the firmware information that macOS sees. Chameleon is one such bootloader. Clover is another. I'll be focusing on Clover in these posts, as it is the current preferred bootloader in the hackintosh community.
Clover functions as an EFI emulator, presenting its customizable view of the computer, including all of the aforementioned tables and other firmware components, to the operating system that it boots. It's able to function within an existing EFI or UEFI environment, as well as within a legacy BIOS one.
The successful creation of a hackintosh essentially boils down to correctly configuring Clover. Although there is sometimes a need for custom kexts to enable more or better functionality of various components, that is generally not needed for basic operation. Custom DSDT modifications, which are presented by Clover to the operating system, will often solve many problems ranging from graphics card initialization to power management, and a lot more.
Configuring a virtual hackintosh is similar to configuring a physical one, with an important difference in that the emulated hardware is nearly identical across most machines. Pretty much the only hardware that is not the same is the CPU, and there are workarounds to address CPU-specific issues.