Previous Part 6. Networking
It might be challenging to digest all that QEMU has to offer.. Don't be scared [of it]. The more you use it, the more comfortable you'll feel. Know that the information that we've gone though is A LOT. Pat yourself in the back if you have made this far! Take your time and familiarize yourself with QEMU. And when you fell ready, continue reading.
If you read this and think that I have made a mistake somewhere or you want me to touch a specific topic PLEASE do so. Any type of feedback (good or bad) is welcome!
Now, it might be hard to know exactly where to start. How do we ACTUALLY start using QEMU? That's the question you probably have right now. Let's answer that and more, together.
Simple answer: Go to this repo's /Machines
folder and start using the scripts there.
Long answer: First ask yourself this: 'Do I really need QEMU or a simple VM?'. Depending on the answer, either use a VM (e.g. VirtualBox) or start configuring your QEMU machine. Let me explain the rest.
QEMU is cool and a great tool to get things done. However, it's NOT a simple and quick virtual machine. Don't get me wrong, it can be a VM if you configure. But the time you spend on that might as well be spent on doing something else, like actually getting things done. So, ask yourself 'Do I really need to use QEMU?'
Reminder that QEMU is an excellent tool to learn new things. So, the question above does not apply to adventurers <3
Now, after that boring AF talk let's get to work. In the Configurations part, we have seen that QEMU has lot's of options to configure. And it's great. This means you can have machine that matches most, if not all, your needs.
Before you start using QEMU straightaway, think and design what you want your machine to be. I can only give some guidance here and not actual steps to follow. Think about these things (in order):
- OS/Kernel: Which operating system you want to use? (e.g. GNU/Linux, Windows, Your Own?!)
- System to emulate: Which system do you need? (e.g. i368, x86_64, ARM, AARC64, PowerPC)
- Machine type: What is your target machine? (e.g. Raspi3, virt, q35, pc, custom)
- CPU to use: Do you want to override your machine's CPU? (e.g. host, EPYC, Skylake, Cortex-A72)
- Core count: How many CPU cores do you want? (e.g. 2, 4, 8)
- Memory size: Amount of memory to allocate. (e.g. 512MiB, 4GiB, 16GiB)
- Devices to use: I/O, Display, Storage etc. (e.g. virtio-kbd, qxl-vga, nvme)
- Networking needs: What is your network needs? (e.g. simple internet access, custom VLAN)
Although the above list doesn't cover everythings, it is a pretty good way to start desigining your QEMU machine. Remember that, QEMU is a tool (also a great way to learn new stuff). So, decide on your needs and then start designing!
These are the steps I generally follow before doing something with QEMU. It is totally personal and you might follow a different approach >.<
After thinking about what you want from your QEMU machine, you can launch your QEMU machine simply by running a series of commands
and arguments
. However, I, and many others, highly suggest you to create a launch script. It doesn't need to be something exotic and 'professional'. Just write your commands there and start it from the terminal.
I hear you asking, "There are too many arguments. Which one should I write first?". The thing is, it does not matter. You may specify your -cpu
last or first. QEMU does not care. BUT! I suggest you to type the most general ones first and others last. Let me give you an example script.
#/usr/bin/env bash
qemu-system-x86_64 -machine virt -cpu virt -m 4G -device usb-kbd -device usb-mouse
You can see that I specified the -machine
option first as it is a more general option. Then, I specify things like -memory
size and -device
s to use. I suggest that you do the same, since it is more intuitive and easy to follow.
An even better way to do things would be to define shell varibles. Instead of just cramping everything into a one giant command, use variables. Here's an example.
#/usr/bin/env bash
MACHINE="-machine virt"
CPU="-cpu virt"
MEMORY="-m 4G"
DEVICES="-device usb-kbd -device usb-mouse"
qemu-system-x86_64 ${MACHINE} ${CPU} ${MEMORY} ${DEVICES} $*
See that I define everything inside variables. This way I can just define a new -device
or change my -m
size without modifying the giant-ass launch command. Note that the last argument $*
is a special shell variable that passes all the command-line arguments to the QEMU as a single string. (e.g. In ./launch_qemu.sh <args>
, the $*
will evaluate to <args>
)
Again, this is what I do to configure my QEMU and create a launch script. It is personal and you may want to use something else. It's totaly okay! Go wild.
The reasons I want you to use a launch script and shell variables is this. Look at the below command:
/Applications/UTM.app/Contents/XPCServices/QEMUHelper.xpc/Contents/MacOS/QEMULauncher.app/Contents/MacOS/QEMULauncher /Applications/UTM.app/Contents/Frameworks/qemu-aarch64-softmmu.framework/Versions/A/qemu-aarch64-softmmu -L /Applications/UTM.app/Contents/Resources/qemu -S -qmp tcp:127.0.0.1:4000,server,nowait -nodefaults -vga none -spice unix=on,addr=/Users/BestUserNameLeft/Library/Group Containers/WDNLXAD4W8.com.utmapp.UTM/C6D43025-8BF5-4B87-A5F5-A8155C6B9DBE.spice,disable-ticketing=on,image-compression=off,playback-compression=off,streaming-video=off,gl=off
-device virtio-ramfb -cpu host -smp cpus=4,sockets=1,cores=4,threads=1
-machine virt, -accel hvf -accel tcg,thread=multi,tb-size=1536 -drive if=pflash,format=raw,unit=0,file=/Applications/UTM.app/Contents/Resources/qemu/edk2-aarch64-code.fd,readonly=on -drive if=pflash,unit=1,file=/Users/BestUserNameLeft/Library/Containers/com.utmapp.UTM/Data/Documents/Windows.utm/Images/efi_vars.fd
-boot menu=on -m 6144 -device intel-hda -device hda-duplex -name Windows -device nec-usb-xhci,id=usb-bus -device usb-tablet,bus=usb-bus.0 -device usb-mouse,bus=usb-bus.0
-device usb-kbd,bus=usb-bus.0 -device qemu-xhci,id=usb-controller-0 -chardev spicevmc,name=usbredir,id=usbredirchardev0 -device usb-redir,chardev=usbredirchardev0,id=usbredirdev0,bus=usb-controller-0.0 -chardev spicevmc,name=usbredir,id=usbredirchardev1 -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1,bus=usb-controller-0.0 -chardev spicevmc,name=usbredir,id=usbredirchardev2 -device usb-redir,chardev=usbredirchardev2,id=usbredirdev2,bus=usb-controller-0.0 -device nvme,drive=drive0,serial=drive0,bootindex=0
-drive if=none,media=disk,id=drive0,file=/Users/BestUserNameLeft/Library/Containers/com.utmapp.UTM/Data/Documents/Windows.utm/Images/windows-11-arm64.qcow2,discard=unmap,detect-zeroes=unmap -device usb-storage,drive=cdrom0,removable=true,bootindex=1,bus=usb-bus.0 -drive if=none,media=cdrom,id=cdrom0 -device virtio-net-pci,mac=9E:E1:25:9D:E7:99,netdev=net0 -netdev vmnet-bridged,id=net0,ifname=en0 -device virtio-serial -device virtserialport,chardev=vdagent,name=com.redhat.spice.0 -
chardev spicevmc,id=vdagent,debug=0,name=vdagent -device virtserialport,chardev=charchannel1,id=channel1,name=org.spice-space.webdav.0 -chardev spiceport,name=org.spice-space.webdav.0,id=charchannel1 -uuid C6D43025-8BF5-4B87-A5F5-A8155C6B9DBE -rtc base=localtime -device virtio-rng-pci
It is crazy right?! This is the default QEMU command that is used by UTM. It looks complicated and hard to follow. Yes it is efficient, as in it is one-line. But, it is very hard for humans to underrstand and change something. That's why you, hopefuly a human being, need to have an easy-to-understand launch script.
By the way, UTM is an amazing thing. You can use it to create pure QEMU machine very easily. It is a great way to learn how complex QEMU machines are configured!
As for you, I have created some example launch scripts that I personally use. Check out the /Machines
folder to explore them! There is a README
for you to use as a quick-start. Feedback is always appreciated 💚!
QEMU defines some shortcuts for you to control the guest machine. Here are some of the ones I found to be useful.
When launched with a display windows, QEMU offers some basic controls on the taskbar. Be sure to check that out as well.
- Release mouse (Display only): GNU/Linux & Windows:
CTRL + ALT + G
, macOS:control + option + G
- Switch to guest (Display only): GNU/Linux & Windows:
CTRL + ALT + 1
, macOS:control + option + 1
- Switch to QEMU Monitor (Display only): GNU/Linux & Windows:
CTRL + ALT + 2
, macOS:control + option + 2
- Toggle between guest & QEMU Monitor (
-nographic
only): All systems:CTRL + A
thenC
- Terminate machine (
-nographic
only): All systems:CTRL + A
thenX
QEMU Monitor is an amazing feature that QEMU offers. It is an advanced topic that is targeted to developers. For this reasons, I won't be explaining it here. Maybe down the road I will... If you are really curious, check out the official documentation QEMU Monitor.
ArxhLinux is a simple and lightweight Linux distribution which follows a rolling release-model for it's packages.1. The official wiki has an amazing Installation guide that I suggest anyone who is interested to at least check out.
I will be explaining how to build a very simple QEMU ArxhLinux x86_64 virtual machine on my ArchLinux host machine (/w Intel i5 6600K
). This is not a through step-by-step tutorial and you can just deviate anytime you want.
This machine can be found at
/Machines
as a basic shell script.
Step 1 - Acquire an installation image
The 'best' place is Arch Linux's Downloads page.
Alternatively use wget
:
$ wget https://geo.mirror.pkgbuild.com/iso/2023.06.01/archlinux-2023.06.01-x86_64.iso
Step 2 - Design a QEMU machine
Here are the basic machine specs I have decided to use:
- Machine:
q35
- CPU:
host
- vCORE:
2
- Accelerator:
KVM
- Memory:
4G
- UEFI/BIOS:
edk2
- I/O:
usb-ehci, usb-kbd, usb-mouse
- Network (Front end):
virtio-net-device
- Network (Back end):
user
- Storage:
nvme
- Display:
virtio-gpu
, - Sound:
intel-hda
andhda-duplex
- Drive-1:
cdrom
(for the installation image) - Drive-2:
qcow2
size of32G
(for thenvme
storage)
Step 3 - Launch the machine
To simplify things I am gonna define some path variables. The EFI_FLASH_PATH
and EFI_VARS_PATH
are your UEFI firmware and variables files. (e.g. /usr/share/edk2-ovmf/x64/QEMU.fd
). The ISO_PATH
is the installation image you acquired from Step 1. And the DISK_PATH
is the disk image that you create using qemu-img
. Don't forget define these variables before running the command below.
Run the following command (append -nographic
if you want no display):
$ qemu-system-x86_64 -machine q35 -cpu host -smp 2 -accel kvm -m 4G -drive if=pflash,format=raw,readonly=on,file=${EFI_FLASH_PATH} -drive if=pflash,format=raw,file=${EFI_VARS_PATH} -device usb-ehci -device usb-kbd -device usb-mouse -device virtio-net-device,netdev=net0 -netdev user,id=net0 -device nvme,drive=hd0,serial=super-fast-boi -device virtio-gpu,xres=1280,yres=720 -device intel-hda -drive id=cd0,media=cdrom,file=${ISO_PATH} -drive id=hd0,if=none,format=qcow2,file=${DISK_PATH}
Common Problem 1: Could not access KVM kernel module: No such file or directory
This error eccours when your host machine does not have the KVM kernel module loaded. There are copule of reasons for that:
- a) The Linux kernel is not built with KVM.
- b)
Intel VT-x
orAMD-V
is not enabled in the UEFI settings. - c) Your CPU does not supports hardware virtualization.
To fix this refer to Hardware Acceleration (Optional).
Common Problem 2: UEFI Shell Appears Instead of the OS/Bootloader
When you first launch a QEMU machine with EDK2
your firmware settings might be incorrect. This can result in a boot order that you might not want (e.g. OS/Bootloader not launching). To correctly setup your UEFI firmware settings Press ESC
during the first boot screen (a.k.a TianaCore screen). OR Type exit
to the UEFI shell if you are using the -nographic
option.
On the UEFI firmware settings screen you can customize your boot order OR simply launch a drive. Feel free to explore the settings, you might find something useful to you.
Creating a QEMU macOS guest machine is a bit tricky. I am nowhere near smrat enough to achieve it. There are also legal considirations as Apple VM's are only supported on Parallels and XCode Virtual Machines.2 So, I won't be personally explaining how to do that here. Although, it is very much possible to do so.
Check out Dhiru Kholia's amazing GitHub repository on how to run macOS on QEMU with KVM. It is an interesting work.