MacOS/KVM

From Segfault
Jump to navigation Jump to search

Installation

With kholia/OSX-KVM it appears to be possible to install macOS as a libvirt virtual machine. The installation was pretty straightforward. In the first step, it recommends to disable[1] to disable the CPU's MSRs:

echo 1 | sudo tee /sys/module/kvm/parameters/ignore_msrs                              # May not be needed at all!

Install some prerequisites:

sudo apt-get install qemu virt-manager dmg2img git wget libguestfs-tools   uml-utilities
sudo dnf install qemu-kvm virt-manager dmg2img git wget libguestfs-tools-c uml_utilities

Clone & use the repository:

git clone https://github.com/kholia/OSX-KVM.git osx-kvm-git && cd osx-kvm-git
./fetch-macOS.py

Once the image has been downloaded, convert it via:

dmg2img -v BaseSystem.dmg BaseSystem.img

Similarly with qemu-img, but with some tuning options set:

qemu-img convert BaseSystem.dmg -O qcow2 -o preallocation=metadata,lazy_refcounts=on,nocow=on BaseSystem.img

Copy the installation scripts and some additional files into our virtual machine location:

mkdir /opt/vm/macos0
cp -p BaseSystem.img OVMF_CODE.fd OVMF_VARS-1024x768.fd OpenCore-Catalina/OpenCore.qcow2 macOS-libvirt-Catalina.xml boot-macOS-Catalina.sh /opt/vm/macos0

These files are needed for:

BaseSystem.img Installation image
OVMF_CODE.fd Open Virtual Machine Firmware
OVMF_VARS-1024x768.fd OVMF variable store[2]
OpenCore-Catalina/OpenCore.qcow2 OpenCore bootloader
Catalina/CloverNG.qcow2 Clover EFI bootloader
macOS-libvirt-Catalina.xml macOS libvirt XML configuration
boot-macOS-Catalina.sh A Qemu start script, adjust as needed.

Create an (empty) system disk:

cd /opt/vm/macos0
qemu-img create -f qcow2 macos_disk0.qcow2 30G

Adjust boot-macOS-Catalina.sh as needed:

$ cat boot-macOS-Catalina.sh
[...]
[...]
          -drive if=pflash,format=raw,readonly,file=OVMF_CODE.fd \
          -drive id=InstallMedia,if=none,file=BaseSystem.img,format=raw \
          -drive id=OpenCore,if=none,snapshot=on,format=qcow2,file=OpenCore.qcow2 \
          -drive id=MacHDD,if=none,file=macos_disk0.qcow2,format=qcow2 \
[...]

Similarily macOS-libvirt-Catalina.xml, of course.

scutil

For some reason our network configuration presented by Libvirt was not working correctly and we had to flush the DNS cache[3] in our now running macOS image:

sudo dscacheutil -flushcache                                                          # The Catalina install image doesn't carry "dscacheutil" any more :(
sudo killall -HUP mDNSResponder

But flushing the DNS cache turned out to be insufficient - we also needed to set[4] a valid DNS server:

sudo scutil
> open
> d.init
> d.add ServerAddresses * 8.8.8.8 9.9.9.9
> set State:/Network/Service/<SERVICE_ID>/DNS
> quit

The important part was the <SERVICE_ID>, a seemingly randomly generated string:

$ echo list | scutil | grep -m1 Network/Service
 subKey [59] = State:/Network/Service/1234A123-ABC1-2345-DEF2-123ABCDEFGHIJK

As the installation would not continue without a working network connection, we really needed to (temporarily) get DNS working here. For that we put a small script on a nearby web server containing the following:

#!/bin/sh
#
# Help:
# > ifconfig en0 10.0.0.123/24
# > route add -net 10.0.0.0/24 -interface en0
# > route add default 10.0.0.1
#
S=$(echo list | scutil | grep -m1 '/Network/Service/' | sed 's|.*/||')

while true; do
date

echo "open
d.init
d.add ServerAddresses * 9.9.9.9 1.1.1.1
set State:/Network/Service/${S}/DNS" | scutil

sleep 10
done

It will adjust the system's DNS configuration with the name servers set above and with that the installation should continue. After booting the installation, execute a Terminal and download the script with curl (use the web server's IP address since we don't have DNS yet) and let it run in the background, preferably with nohup. As nohup may not be available, detach the script from the current session so it will not get terminated when Terminal.app is closed:

curl -L http://10.0.0.3/foo/osx_network_quirk.sh.txt > /tmp/n.sh
chmod +x /tmp/n.sh
/tmp/n.sh &
disown

Now Terminal.app can be closed and the installation process should continue.

Links

References