Installing virt-manager will install qemu as dependency.
sudo apt install virt-manager
I had to restart Ubuntu to get virtd privilegies.
Download source code https://www.qemu.org/download/#source
Compile with just one target --target-list=x86_64-softmmu
so you don'r need to compile other systems that we don't need, unless you really need them. There is an issue of using -net user
that needs to be compiled with enable-slirp
(install libslirp-dev
). And need to set prefix as /usr
, if not, it will install in /usr/local
and will cause problems with libvirtd
.
sudo apt install libslirp-dev
wget https://download.qemu.org/qemu-7.2.0.tar.xz
tar xvJf qemu-7.2.0.tar.xz
cd qemu-7.2.0
./configure --target-list=x86_64-softmmu --enable-slirp --prefix=/usr
make
sudo make install
https://github.com/tianocore/tianocore.github.io/wiki/Build-Instructions
https://github.com/tianocore/tianocore.github.io/wiki/Getting-Started-with-EDK-II
Install dependencies
sudo apt install build-essential uuid-dev iasl git nasm python-is-python3
https://github.com/tianocore/tianocore.github.io/wiki/Common-instructions
Compile BaseTools
and setup project variables (it will add some variables to your ENV)
git clone https://github.com/tianocore/edk2
cd edk2
git submodule update --init
make -C BaseTools
source edksetup.sh
Edit the file edk2/Conf/target.txt
with setting below. Will build OVMF module (boot system), release target (or DEBUG), for x64 and using gcc.
ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc
TARGET = RELEASE
TARGET_ARCH = X64
TOOL_CHAIN_TAG = GCC5
Run build
to start building OVMF (it will build a couple dependent modules)
build
It will create our boot bin file /path/to/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd
Find the /dev/X that matches your drive
sudo fdisk -l
In my case it is /dev/nvme0n1
.
My Windows is in partition /dev/nvme0n1p3
Check if your Linux has modules loop and linear enabled (if there is no error message, you are good)
sudo modprobe loop
sudo modprobe linear
Create EFI metadata
dd if=/dev/zero of=$HOME/some/location/efi1 bs=1M count=100
dd if=/dev/zero of=$HOME/some/location/efi2 bs=1M count=1
Create loopback
sudo losetup -f $HOME/some/location/efi1
sudo losetup -f $HOME/some/location/efi2
Verify which loopX they were created
losetup -a
In my case ef1 is /dev/loop3
and ef2 is /dev/loop5
Install virtual RAID tool mdadm
sudo apt install mdadm
Put them in order = efi1
-> windows
-> ef2
sudo mdadm --build --verbose /dev/md0 --chunk=512 --level=linear --raid-devices=3 /dev/loop3 /dev/nvme0n1p3 /dev/loop5
Some useful commands
sudo mdadm --stop /dev/md0
sudo mdadm --remove /dev/md0
cat /proc/mdstat
Check the sizes of ef1 and ef2
sudo fdisk -l ef*
--------------------------
Disk efi1: 100 MiB, 104857600 bytes, 204800 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk efi2: 1 MiB, 1048576 bytes, 2048 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
In this case ef1 is 204800
sectors and ef2 is 2048
sectors.
Use parted to create the partitions in the virtual RAID
sudo parted /dev/md0
(parted) unit s
(parted) mktable gpt
(parted) mkpart primary fat32 2048 204799 # depends on size of efi1 file (above with fdisk = 204800)
(parted) mkpart primary ntfs 204800 -2049 # depends on size of efi1 and efi2 files (above with fdisk = 2048)
(parted) set 1 boot on
(parted) set 1 esp on
(parted) set 2 msftdata on
(parted) name 1 EFI
(parted) name 2 Windows
(parted) quit
Format the EFI partition
sudo mkfs.msdos -F 32 -n EFI /dev/md0p1
We need to change the owner of md0
chown $USER:$USER /dev/md0
Boot QEMU using the OVMF compiled above and using a Windows ISO https://www.microsoft.com/en-us/software-download/windows11
qemu-system-x86_64 \
-bios $HOME/path/to/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive file=/dev/md0,media=disk,format=raw \
-cpu host -enable-kvm -m 2G \
-cdrom $HOME/Win11_22H2_English_x64v1.iso
It will start the Windows installation process, but press Shift+F10
to open a terminal.
Assign a letter to EFI volume
diskpart
DISKPART> list disk
DISKPART> select disk 0 # Select the disk
DISKPART> list volume # Find EFI volume (partition) number
DISKPART> select volume 2 # Select EFI volume
DISKPART> assign letter=B # Assign B: to EFI volume
DISKPART> exit
Back in the terminal, make Windows copy boot files in the EFI partition
bcdboot C:\Windows /s B: /f ALL
Run List Hardware to check your network adapters.
lshw -C network
In my case my ethernet was showing as generic
. I had to go to Realtek website, download the driver and install.
https://www.realtek.com/en/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-pci-express-software
https://www.realtek.com/en/component/zoo/advanced-search/72?Itemid=276
cd ~/Downloads
untar r8168-xxxx.tar.bz2
cd r8168-xxxx
sudo ./autorun.sh # this will remove generic and install the driver
shutdown -r 0 # reboot
This doesn't work with WiFi because wifi protocols and cards are not designed to use bridge interfaces, this only works with Ethernet cable connections.
https://www.youtube.com/watch?v=6435eNKpyYw
But this is necessary for Linux VMs too.
# find your ethernet adapter (mine was enp7s0), and the IP it is using (192.168.x.x/y)
ip a
# disable your ethernet
ip link set enp7s0 down
# if you wait a few seconds the IP should be gone without this command
ip addr del 192.168.x.x/y dev enp7s0
# make sure systemd-networkd is stopped
systemctl status systemd-networkd
systemctl stop systemd-networkd
# create the bridge br0
ip link add name br0 type bridge
# make you ethernet bounded to the bridge
# the bridge will receive the IP from our gateway/router DHCP
ip link set enp7s0 master br0
# install some helper tools
apt install net-tools
Create systemd-networkd config files
# start the br0 device
cat <<EOF > /etc/systemd/network/br.netdev
[NetDev]
Name=br0
Kind=bridge
EOF
# bind br0 to the ethernet adapter
cat <<EOF > /etc/systemd/network/1-br0-bind.network
[Match]
Name=enp7s0
[Network]
Bridge=br0
EOF
# make the br0 get an IP from the gateway/router DHCP
cat <<EOF > /etc/systemd/network/2-br0-dhcp.network
[Match]
Name=br0
[Network]
DHCP=ipv4
EOF
# the systemd-networkd will create the bridge for us now
ip link delete br0
ip link set enp7s0 down
systemctl enable systemd-networkd
systemctl start systemd-networkd
# check if br0 got an IP and the ethernet has br0 as master
ip a
In Virt-Manager, create you VM, open the VM informations, select NIC (Network Interface Controller). In "Network source" select "Bridge device..." with name "br0".
Do this for all VMs that need external connection (Linux or Windows).
But Windows need Virtio drivers to work.
Download the driver from Fedora. Download the ISO that contains the drivers.
https://docs.fedoraproject.org/en-US/quick-docs/creating-windows-virtual-machines-using-virtio-drivers/
https://github.com/virtio-win/virtio-win-pkg-scripts/blob/master/README.md
Add the ISO to a virtual CD-ROM device on the Windows VM.
https://linuxhint.com/install_virtio_drivers_kvm_qemu_windows_vm/
Now, you are ready to boot to Windows from inside Qemu.
Right click the start menu, select Device Manager
. Go to the "Other devices", right click "Ethernet", select Update drivers, choose Browse local, select the D: (the CD-ROM), and search. Windows should install the correct driver.
Do the same for any other device that needs a driver. I had two "PCI device" and the "Displar adapter" that needed an update.
Restart the VM!
I could never make this work under WiFi, but I didn't know about the bridge or the Virtio drivers. I don't think I'll try to make it work in WiFi because now I know how to do it in Ethernet.
Get a random MAC address that needs to start with 52:54
https://wiki.archlinux.org/title/QEMU#Networking
printf -v macaddr "52:54:%02x:%02x:%02x:%02x" $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff )) $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff ))
echo $macaddr
Save it so that the DHCP gives the virtual machine the same IP every time. If you leave random, a new IP will be generated.
qemu-system-x86_64 \
-bios $edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive file=/dev/md0,media=disk,format=raw \
-cpu host \
-enable-kvm \
-m 6G \
$@
# -drive format=raw,file=/dev/nvme0n1p3 \
# sudo qemu-system-x86_64 \
-bios $edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-enable-kvm \
-cpu host \
-smp 8 \
-m 6G \
-hda /dev/nvme0n1p3 \
$@
Run QEMU using script below run_qemu