Using qemu-system-x86_64
The qemu-system-x86_64 command runs a virtual machine using the x86_64 (also known as AMD64) architecture, which implements the modern Intel/AMD instruction set. This document explains how to use qemu-system-x86_64 to run virtual machines booted using both BIOS and UEFI modes.
Video Demonstration
Initial Preparation
These steps only need to be completed once when the virtual machine is first created. When restarting the VM at a later time, simply double-click the batch file.
- Download the latest Alpine Linux “Virtual” ISO file for the x86_64 architecture.
- Create a dedicated directory (folder) on your host system to contain this virtual machine.
- Move the downloaded ISO file from the first step into the newly created directory.
- Open a terminal window, and use the cd command to navigate to the directory you created.
- Create the disk image by running the following command:
qemu-img create -f qcow2 alpine.qcow2 40G
- Prepare a script to make it easier to run QEMU (see below).
- Run your script to launch the virtual machine.
BIOS Booting
To boot Alpine Linux in BIOS mode, use a command like the following. Note that you may need to adjust the Alpine Linux ISO version, since new versions are released regularly.
qemu-system-x86_64 \
-name "Alpine Linux x86_64" \
-machine type=pc-q35-6.0 \
-accel tcg \
-cpu qemu64 \
-smp 2 \
-m 2048 \
-rtc base=utc \
-drive file="alpine.qcow2",if=virtio,format=qcow2 \
-boot order=cd,menu=on \
-display gtk \
-device virtio-vga \
-nic user,id=NAT,model=virtio-net-pci,mac=02:00:00:00:00:01 \
-device qemu-xhci \
-device usb-tablet \
-cdrom "alpine-virt-3.16.2-x86_64.iso"
Let’s look at the meaning of the arguments to qemu-system-x86_64:
- -name
- This is a human-readable name for the VM. In this case, I called it “Alpine Linux x86_64”, but it really could be named anything you want.
- -machine
- This is the machine type to emulate. The pc-q35-6.0 machine is a conservative choice.
- -accel
- This argument specifies the accelerator to use. If you haven’t configured an accelerator, or if you’re unsure, use the Tiny Code Generator (“tcg”) option. The VM will run more slowly without an accelerator, but it will still work.
- -cpu
- To emulate a particular CPU model, specify it here. Most of the time, you can get away with just using the generic “qemu64” CPU.
- -smp
- In recent versions of QEMU (starting from version 6.2), the number after -smp specifies the number of CPU cores to give to the virtual machine. (In older versions of QEMU, it used to specify the number of virtual CPU chips that were emulated.) My example gives the guest 2 cores, but you can increase this number. A good rule of thumb is to give a virtual machine no more than half the number of physical CPU cores you have available on your host system.
- -m
- This option specifies the amount of RAM in MiB (mebibytes, or binary megabytes, which are multiples of 220). In this example, I specified 2048, which corresponds to 2 GiB RAM. Be careful not to give the guest system more RAM than your host computer physically has! Leave at least 2 GiB for the host operating system.
- -rtc
- The -rtc argument specifies the type of real time clock to give to the guest machine. UNIX (and therefore Linux and BSD) guests expect the rtc to use UTC time, while Windows guests expect the rtc to use localtime. Remember this setting is based on the guest system, not whatever system you have on your host computer. In short, if you are creating a Windows virtual machine, set -rtc base=localtime. Otherwise, leave this option as I have it in my example.
- -drive
- Each virtual hard disk that you connect to the virtual machine will have a -drive argument associated with it. There are a significant number of parameters that can be specified for a drive, depending on what type of disk image you’re using, what type of disk controller the virtual machine will support, and so forth. Most of the time, you should be able to use my example and just change the filename to the name of the disk image file you create for the corresponding VM.
- -boot
- This parameter sets the boot order. For historical reasons, QEMU uses the DOS drive letter naming conventions. Therefore, order=cd tries to boot from the virtual hard disk (C:) first, then falls back to any attached virtual CD-ROM drive (D:) second. A boot menu is available briefly when the VM starts, which is helpful for overriding the boot order on the fly. Leave menu=on in place to enable this menu.
- -display
- QEMU supports different kinds of display window for the virtual machine’s screen. Depending on what you’re doing with the VM, and what outputs are available on your computer, you might use a different display. I recommend “gtk” if it is available for most general use cases. If that doesn’t work for some reason, try “sdl”. On a Mac system, you could also try “cocoa”.
- -device virtio-vga
- This might be a little confusing at first, but displaying output in QEMU is controlled by two different things. The -display argument specifies what kind of window to use for the output on the host system. However, we also have to specify what kind of video card to emulate for the guest system. The “virtio-vga” video card should work with any reasonably modern guest OS.
- -nic
- The -nic argument is a shortcut that configures the network that the virtual machine will see. QEMU supports a wide array of different network configurations. However, if you just need your Internet connection to work inside your VM, the “user” network is sufficient. You can set the MAC address of your virtual network card to any value, but the standard for locally-assigned MAC addresses is to have the twos bit set in the first octet of the MAC address. The easiest way to do this is to start your VM MAC addresses with 02:.
- -device qemu-xhci
- This option enables the Extensible Host Controller Interface (xHCI), which is a USB 3.0 host controller.
- -device usb-tablet
- This option attaches a USB drawing tablet to a virtual USB port and maps your mouse pointer to that tablet. If you need to run really old operating systems as virtual machines (for example, ancient Linux distributions), USB tablet support might not exist. However, this option should be OK for any reasonably modern guest system. Using the tablet instead of traditional mouse emulation means that QEMU doesn’t need to grab your mouse and restrict it to the virtual machine window during use.
- -cdrom
- On emulated PC hardware, the -cdrom option connects an ISO file to a virtual CD-ROM drive. This option will work with any ISO file, so it also supports images of DVD-ROMs and other optical drives. Alternatively, you could also specify the ISO file using a -drive argument with readonly=on set.
Scripting VM Execution
Starting the virtual machine by hand with the full command line each time would be cumbersome and error-prone. Consequently, I recommend creating a script that contains the QEMU command. The following example is a Bourne shell script for Linux or macOS.
#!/bin/sh
qemu-system-x86_64 \
-name "Alpine Linux x86_64" \
-machine type=pc-q35-6.0 \
-accel tcg \
-cpu qemu64 \
-smp 2 \
-m 2048 \
-rtc base=utc \
-drive file="alpine.qcow2",if=virtio,format=qcow2 \
-boot order=cd,menu=on \
-display gtk \
-device virtio-vga \
-nic user,id=NAT,model=virtio-net-pci,mac=02:00:00:00:00:01 \
-device qemu-xhci \
-device usb-tablet \
-cdrom "alpine-virt-3.16.2-x86_64.iso"
echo "QEMU has finished. Press Enter to continue."
read throwaway
I have downloadable templates in Bourne shell script format for Linux/macOS and batch file and PowerShell formats for Windows. These templates can be used as a starting point for your own VM scripts.
UEFI Booting
To boot in UEFI mode instead of BIOS mode, first copy the edk2-i386-vars.fd file from the QEMU share directory to your virtual machine directory. The location of this directory varies based on your host system. In Linux, as shown in the following example, look in /usr/share/qemu for this file. On a Mac, look in /opt/homebrew/share/qemu or /usr/local/share/qemu, depending on what kind of CPU you have. Look in C:\Program Files\qemu\share on a Windows host.
Once you’ve copied the file, adjust the qemu-system-x86_64 command like this, again substituting the path to your QEMU share directory for /usr/share/qemu:
qemu-system-x86_64 \
-name "Alpine Linux x86_64 UEFI" \
-machine type=pc-q35-6.0 \
-accel tcg \
-cpu qemu64 \
-smp 2 \
-m 2048 \
-rtc base=utc \
-drive if=pflash,format=raw,file="/usr/share/qemu/edk2-x86_64-code.fd",readonly=on \
-drive if=pflash,format=raw,file=edk2-i386-vars.fd \
-drive file="alpine.qcow2",if=virtio,format=qcow2 \
-boot menu=on \
-display gtk \
-device virtio-vga \
-nic user,id=NAT,model=virtio-net-pci,mac=02:00:00:00:00:01 \
-device qemu-xhci \
-device usb-tablet \
-cdrom alpine-virt-3.16.2-x86_64.iso