目錄

使用 QEMU 創建 FreeBSD 16 Current VM

QEMU

基本的操作如下,來是 Gemini:

/qemu-freebsd/image.png

但我們在切換 FreeBSD tty 會用到 Ctrl + Alt 所以反而會切到 Linux host machine 的 TTY,可以在 QEMU Monitor 輸入 sendkey ctrl-alt-f2 手動輸入切換。

VirtIO

在沒有 VirtIO 的年代,虛擬機(Guest)如果要叫宿主機(Host)做事情,必須假裝自己是一台擁有舊硬體的實體機(比如模擬成一張 1990 年代的 Intel 網卡)。這種「演戲」的過程非常消耗 CPU 效能。

VirtIO 的運作原理:半虛擬化 (Para-virtualization)

  • 前端 (Front-end):跑在你的 FreeBSD 虛擬機裡。它知道自己是虛擬的,所以它不傳送複雜的硬體訊號,而是直接把數據丟到記憶體的一塊「共享區域」。
  • 後端 (Back-end):跑在你的 QEMU/KVM 裡。它直接從共享區域抓數據,交給實體硬體處理。

所以這邊可能可以用:

  1. VirtIO 模擬網卡 and Disk
  2. E1000 模擬 Intel 網卡 and SATA 硬碟

我們這邊使用第一種,FreeBSD 甚至內建 Kenrel 就有一些 virtio 驅動,清參考 Man page VIRTIO(4)

FreeBSD 安裝

我們先用簡單的 amd64 ISO 檔案 FreeBSD-16.0-CURRENT-amd64-20260330-e6eba5076929-284768-disc1.iso

kola:~/proj/freebsd_16_20260330$ ls
FreeBSD-16.0-CURRENT-amd64-20260330-e6eba5076929-284768-disc1.iso
kola:~/proj/freebsd_16_20260330$ qemu-img create -f qcow2 freebsd16.qcow2 50G
Formatting 'freebsd16.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=53687091200 lazy_refcounts=off refcount_bits=16

kola:~/proj/freebsd_16_20260330$ qemu-system-x86_64 \
  -m 8G \
  -cpu host \ # 這代表直接把 Linux 主機的 CPU 特性傳遞給虛擬機
  -smp 6 \
  -enable-kvm \ # 啟動 Linux 核心加速
  -drive file=freebsd16.qcow2,if=virtio \ # 告訴 FreeBSD 這不是傳統的 IDE 或 SATA 硬碟,而是高效能的 VirtIO 區塊設備
  -cdrom FreeBSD-16.0-CURRENT-amd64-20260330-e6eba5076929-284768-disc1.iso \ # 將 ISO 檔掛載到虛擬光碟機。安裝完成後,這行其實可以拿掉
  -net nic,model=virtio -net user \ # 虛擬網卡使用 VirtIO 驅動。在 FreeBSD 裡會顯示為 vtnet0
  -vga virtio \ # 模擬一張 VirtIO GPU。這是目前 QEMU 裡最強大的虛擬顯卡,支援 3D 加速
  -display gtk,gl=on \ # gtk: 使用 Linux 系統常見的 GTK 視窗來顯示 QEM
  -device virtio-tablet-pci \ # 這本來是為了實現「游標無縫進出」虛擬機的技術
  -audiodev pa,id=snd0 \ # 讓 QEMU 的聲音輸出到 Linux 宿主機的 PulseAudio
  -device intel-hda # 在虛擬機裡模擬一個 Intel 高傳真音效卡硬體
  -device hda-duplex,audiodev=snd0 # 模擬的硬體(hda-duplex,支援輸入輸出)與剛才定義的後端(snd0)連接起來

qemu-system-x86_64 \
  -m 8G \
  -cpu host \
  -smp 6 \
  -enable-kvm \
  -drive file=freebsd16.qcow2,if=virtio \
  -net nic,model=virtio -net user \
  -vga virtio \
  -display gtk,gl=on \
  -device virtio-tablet-pci \
  -audiodev pa,id=snd0 \
  -device intel-hda \
  -device hda-duplex,audiodev=snd0

(qemu-system-x86_64:241929): Gtk-WARNING **: 19:23:20.366: Theme parsing error: gtk.css:2560:38: Junk at end of value for background

之後就不需要 cdrom 參數了,但因為 -device virtio-tablet-pci,virtio-tablet 傳送的是「絕對座標」(例如:滑鼠現在在螢幕的 500, 300 處)。如果 FreeBSD 內核沒有正確載入 virtio_gpu 驅動來告訴系統「螢幕現在解析度是多少」,系統就會不知道這座標該往哪擺,最後只能讓下游標卡在螢幕正中央。

Mouse cursor not detected on FreeBSD virtual machine on Qemu

根據上面文章,在虛擬化環境中,普通的「滑鼠(Mouse)」通常是以相對座標運作,這在圖形介面(X11)中常導致虛擬機滑鼠與主機滑鼠不同步。為了解決這個問題,通常會改用「平板電腦(Tablet)」模式,它使用絕對座標,能讓滑鼠指哪打哪。

然而,FreeBSD 的舊版本核心對 QEMU 提供的 USB Tablet 或 VirtIO Tablet 支援並不完善,需要額外的驅動程式。

  • 舊方法(針對 FreeBSD 12 或更早):需要手動安裝 utouch-kmod 驅動,並在 virt-manager 裡將輸入裝置設為 “EvTouch USB Graphics Tablet”
  • 新方法(針對 FreeBSD 13、14 及更新版本):論壇最後一則回覆(#25)指出,現在不需要安裝額外套件了。FreeBSD 核心現在內建了 hms(4) 驅動來支援 HID 滑鼠/平板設備,但預設沒啟用

所以改成以下用 -usb -device usb-tablet,這讓 QEMU 模擬一個實體 USB 繪圖板。FreeBSD 內核裡的 hms 和 usbhid 驅動對這個裝置的支援非常穩,不管有沒有 3D 加速,它都能 100% 正常移動。

qemu-system-x86_64 \
  -m 8G \
  -cpu host \
  -smp 6 \
  -enable-kvm \
  -drive file=freebsd16.qcow2,if=virtio \
  -net nic,model=virtio -net user \
  -vga virtio \
  -display gtk,gl=on \
  -usb -device usb-tablet \
  -audiodev pa,id=snd0 \
  -device intel-hda \
  -device hda-duplex,audiodev=snd0

網路

User-mode Networking (SLIRP),這模式是 QEMU 的預設值。你可以把它想像成 「QEMU 內建的一個小型 Proxy 伺服器」。

QEMU 會攔截虛擬機發出的所有 TCP/UDP 封包,然後在 Linux 宿主機(Host)上以普通使用者的身分重新發送這些請求。

因為在 Linux 裡,發送 ICMP(Ping)封包需要 Raw Socket 權限,而普通使用者啟動的 QEMU 行程沒有這個權限,所以 SLIRP 乾脆不模擬 ICMP。

TAP 模式(最推薦,最像實體機) 這是在 Linux 上實現虛擬化最標準的做法。它會在你的 Linux 裡建立一個虛擬網卡(例如 tap0),然後透過 Bridge(網橋) 把這張虛擬網卡跟你的實體網卡(例如 eth0)連在一起。 效果:FreeBSD 會從你的路由器(Router)直接拿到一個跟 Linux 主機同區網的 IP(例如 192.168.1.50)。 能力:可以被 Ping,可以從 Linux 直接 SSH 進去,甚至可以在區網內玩檔案共享。

Port Forwarding(懶人折衷法) 如果你不想搞複雜的網橋,但又想連進 FreeBSD,可以在原本的 SLIRP 模式加一個「傳送門」。 指令範例:-netdev user,id=n1,hostfwd=tcp::2222-:22 效果:你在 Linux 連線 localhost:2222,封包會被轉發到虛擬機的 22 埠。

Passthrough(硬體直通) 如果你有兩張實體網卡,可以直接把其中一張「送給」虛擬機。 效果:效能最高,但那張網卡在 Linux 宿主機上會消失,專供 FreeBSD 使用。


VMware 預設通常是 NAT 模式 或 Bridged (橋接) 模式。雖然聽起來跟 QEMU 的 User Mode (SLIRP) 很像,但底層實現完全不同:

VMware 的 NAT 模式:它在你的 Linux 宿主機中安裝了內核級別的驅動程式(這就是為什麼你安裝 VMware 時需要輸入密碼,還要編譯一堆 vmnet 模組)。這些驅動讓 VMware 擁有了「特權」,可以直接在 Linux 核心層級處理網路封包,模擬出一台功能完整的虛擬路由器。

QEMU 的 User Mode (SLIRP):它是一個純粹的使用者層級 (User-space) 程式。它不觸碰內核,只靠標準的系統呼叫來傳輸資料。因為它沒有特權,所以無法偽造 ICMP (Ping) 封包。

桌面環境

有驅動(VirtIO GPU):可以支援解析度自動調整、雙螢幕,以及最重要的 OpenGL 加速,這對 KDE 6 的特效至關重要。 包含在 drm-kmod 裡面

看要不要安裝 “noto-2.0”?

sudo pkg install -y xorg
sudo pw groupmod video -m [user]
sudo pkg install kde
sudo pkg install dbus # 其實不用跑已經安裝了
sudo sysrc dbus_enable="YES"
sudo sysrc net.local.stream.recvspace=65536
sudo sysrc net.local.stream.sendspace=65536
sudo pkg drm-kmod # 包含 QEMU 的 virtio_gpu.ko 驅動
# sysrc kld_list+="virtio_gpu"

### ----------------------------------------- ###

sudo pkg install plasma6-sddm-kcm # KDE 的控制模組 (KCM),讓你可以在 KDE 的「系統設定」介面裡直接設定 SDDM 登入畫面
sudo pkg install sddm  # Simple Desktop Display Manager。雖然是獨立計畫,但它是 KDE 官方推薦的登入程式,支援 X11 與 Wayland

sudo sysrc hald_enable="YES"
sudo sysrc sddm_enable="YES"
sudo sysrc snd_driver_load="YES"

Debug

進度 ISO loader prompt。

/qemu-freebsd/image-2.png

/qemu-freebsd/image-1.png

set currdev=disk0p2:
ls /boot/kernel/kernel
load /boot/kernel/kernel
boot

Reference