00 QEMU nedir
QEMU (Quick Emulator), hem tam sistem hem de kullanıcı alanı emülasyonu yapabilen, açık kaynaklı bir makine öykünücüsü ve sanallaştırma aracıdır.
Full-system vs usermode emulation
QEMU iki temel modda çalışır. Full-system modunda (qemu-system-*) CPU, bellek, disk, ağ kartı ve diğer çevre birimlerinin tamamını taklit eder — sanki gerçek bir donanım üzerinde çalışıyorsunuz gibi kernel'ı boot eder. Usermode modunda (qemu-*) ise yalnızca kullanıcı alanı binary'lerini çalıştırır; sistem çağrılarını host kernel'a yönlendirir. Embedded geliştirmede genellikle full-system modu kullanılır.
| Mod | Binary | Ne taklit eder | Kullanım |
|---|---|---|---|
| Full-system | qemu-system-arm | CPU + bellek + tüm donanım | Kernel boot, tam sistem test |
| Usermode (Linux) | qemu-arm | Yalnızca CPU + syscall çevirisi | Cross-compile binary test, chroot |
| Usermode (BSD) | qemu-arm-bsd | BSD syscall çevirisi | BSD target binary test |
TCG vs KVM
QEMU, CPU emülasyonunu iki farklı yöntemle gerçekleştirir. TCG (Tiny Code Generator), misafir mimarinin makine kodunu host mimarisine çalışma anında dönüştürür (JIT derleme). Bu sayede host ile misafir farklı mimarilerde olabilir — örneğin x86-64 host üzerinde ARM kodunu çalıştırabilirsiniz. KVM ise Linux çekirdeğinin sanallaştırma altyapısını kullanır; misafir ve host aynı mimariyi paylaşırken donanım hızlanması sağlar. Embedded geliştirmede (ARM cross-emulation) TCG kullanılır.
ARM guest code → TCG frontend (ARM decode) → TCG IR → TCG backend (x86-64 codegen) → native execution
Desteklenen mimariler
| Mimari | QEMU binary | Örnek hedefler |
|---|---|---|
| ARM 32-bit | qemu-system-arm | Cortex-A8/A9, Versatile PB, BeagleBone |
| ARM 64-bit (AArch64) | qemu-system-aarch64 | Cortex-A53/A72, Raspberry Pi 3/4, virt |
| RISC-V 32/64 | qemu-system-riscv64 | SiFive HiFive, virt, spike |
| MIPS | qemu-system-mips | Malta, MIPS32 router SoC |
| x86 / x86-64 | qemu-system-x86_64 | i440FX, Q35, microvm |
| PowerPC | qemu-system-ppc | PowerNV, pseries |
Embedded geliştirici için değeri
Bu bölümde
- QEMU = full-system emülasyon (qemu-system-*) + usermode emülasyon (qemu-arm)
- TCG: misafir mimarisi → JIT → host native kod; ARM emülasyonu için TCG kullanılır
- ARM, AArch64, RISC-V, MIPS, x86, PowerPC destekli
- CI pipeline'da board olmadan kernel boot + test: embedded CI'ın temeli
01 Kurulum ve ilk çalıştırma
QEMU'nun kurulumundan ilk ARM Linux boot'una kadar tüm adımlar — qemu-system-arm -M versatilepb ile dakikalar içinde çalışan bir sistem.
Kurulum
# Full-system emülatörleri kur
sudo apt-get install -y \
qemu-system-arm \
qemu-system-aarch64 \
qemu-system-misc \
qemu-utils
# Usermode emülatörleri kur (cross-binary test için)
sudo apt-get install -y \
qemu-user-static \
binfmt-support
# Versiyon kontrolü
qemu-system-arm --version
# QEMU emulator version 8.2.2
# Copyright (c) 2003-2024 Fabrice Bellard and the QEMU Project developers
İlk çalıştırma: ARM Versatile PB
# Minimal ARM Linux sistemi indir (Buildroot önceden derlenmiş)
wget https://buildroot.org/downloads/buildroot-2024.02.tar.gz
tar xf buildroot-2024.02.tar.gz && cd buildroot-2024.02
make qemu_arm_versatile_defconfig
make -j$(nproc)
# Kernel + initrd ile boot (disk olmadan)
qemu-system-arm \
-M versatilepb \
-kernel output/images/zImage \
-initrd output/images/rootfs.cpio.gz \
-append "console=ttyAMA0 rdinit=/sbin/init" \
-serial stdio \
-nographic
# QEMU'dan çıkmak için: Ctrl+A ardından X
Temel parametreler
versatilepb, virt, raspi3b vb. (bkz. Bölüm 02)Seri konsol yapılandırması
# seri → stdio (en yaygın, tek terminal)
qemu-system-arm -serial stdio -nographic ...
# seri → TCP telnet (başka terminalden bağlan)
qemu-system-arm -serial "telnet:localhost:4321,server,nowait" ...
# Bağlan: telnet localhost 4321
# İkinci seri port (loglama)
qemu-system-arm \
-serial stdio \
-serial "file:/tmp/uart1.log" ...
# seri → /dev/pts (pty — minicom ile bağlanmak için)
qemu-system-arm -serial pty ...
-nographic kullanıldığında QEMU monitor'e Ctrl+Alt+2 ile değil, Ctrl+A c ile geçilir. QEMU'dan çıkmak için Ctrl+A x veya monitor'de quit komutu kullanılır.
Bu bölümde
qemu-system-arm -M versatilepb -kernel zImage -initrd rootfs.cpio.gz: minimal boot-append "console=ttyAMA0": kernel seri konsolu ttyAMA0'a yönlendirir-nographic -serial stdio: grafik pencere olmadan terminalde seri çıktı- Çıkış: Ctrl+A x; monitor: Ctrl+A c
02 Makine tipleri ve CPU
QEMU'nun desteklediği makine tipleri, CPU modelleri, SMP ve bellek konfigürasyonu — embedded hedef için doğru makineyi seçmek.
Mevcut makine tiplerini listeleme
# ARM 32-bit makine listesi
qemu-system-arm -M "?"
# Supported machines are:
# akita Sharp SL-C1000 (Akita) PDA (PXA270)
# ast2500-evb Aspeed AST2500 EVB (ARM1176)
# bcm2836 Raspberry Pi 2B (BCM2836)
# collie Sharp SL-5500 (Collie) PDA (SA-1110)
# cubieboard cubietech cubieboard (Cortex-A8)
# imx25-pdk ARM i.MX25 PDK board (ARM926)
# musicpal Marvell 88w8618 / MusicPal (ARM926EJ-S)
# netduino2 Netduino Plus 2 Machine (Cortex-M3)
# none empty machine
# raspi0 Raspberry Pi Zero (BCM2835)
# raspi1ap Raspberry Pi A+ (BCM2835)
# raspi2b Raspberry Pi 2B (BCM2836)
# realview-eb ARM RealView Emulation Baseboard (ARM926EJ-S)
# stellaris Luminary Micro Stellaris (Cortex-M3)
# versatilepb ARM Versatile/PB (ARM926EJ-S)
# virt QEMU 2.6+ ARM Virtual Machine (cortex-a15)
# ...
# AArch64 makine listesi
qemu-system-aarch64 -M "?"
# raspi3ap Raspberry Pi 3A+ (BCM2837)
# raspi3b Raspberry Pi 3B (BCM2837)
# raspi4b Raspberry Pi 4B (BCM2711)
# sbsa-ref SBSA-REF Machine
# virt QEMU 2.6+ ARM Virtual Machine
CPU modeli seçimi
# Mevcut CPU modellerini listele
qemu-system-aarch64 -M virt -cpu "?"
# Available CPUs:
# cortex-a35
# cortex-a53
# cortex-a55
# cortex-a57
# cortex-a72
# cortex-a76
# max (en gelişmiş QEMU CPU — tüm özellikler etkin)
# Cortex-A53 ile virt makinesi
qemu-system-aarch64 \
-M virt \
-cpu cortex-a53 \
-m 512M \
-kernel Image \
-nographic
# ARM 32-bit — Cortex-A9 (i.MX6 gibi SoC'lar için)
qemu-system-arm \
-M virt \
-cpu cortex-a9 \
-m 256M \
-kernel zImage \
-nographic
SMP (Çok çekirdek) ve bellek
# 4 çekirdek, 1 GB RAM
qemu-system-aarch64 \
-M virt \
-cpu cortex-a53 \
-smp 4 \
-m 1G \
-kernel Image \
-nographic
# SMP gelişmiş: socket/core/thread topolojisi
qemu-system-aarch64 \
-M virt \
-cpu cortex-a72 \
-smp "cpus=4,sockets=1,cores=4,threads=1" \
-m 2G \
-kernel Image \
-nographic
# Bellek boyutu birimleri: M (MiB), G (GiB)
# -m 256M → 256 MiB
# -m 1G → 1024 MiB
# -m 512 → 512 MiB (birim belirtilmezse MiB varsayılır)
virt makinesi — embedded için neden tercih edilir
Yeni bir projeye başlarken makine olarak virt ve CPU olarak cortex-a53 kombinasyonunu tercih edin. Bu kombinasyon, gerçek dünya ARM64 SoC'larının (i.MX8, RK3328, MT8183) donanım davranışını en iyi yansıtan ve en geniş kernel desteğine sahip seçenektir.
Bu bölümde
qemu-system-arm -M ?ve-cpu ?: desteklenen makine ve CPU listesi-M virt -cpu cortex-a53: embedded ARM64 için önerilen kombinasyon-smp 4 -m 512M: 4 çekirdek, 512 MiB RAM konfigürasyonu- versatilepb: ARM 32-bit geliştirme; virt: modern ARM32/ARM64
03 Storage simülasyonu
Sanal disk, SD kart ve NOR/NAND flash simülasyonu — qemu-img ile image oluşturma ve -drive parametreleri.
qemu-img ile disk image oluşturma
# Ham (raw) disk image — 512 MB SD kart simülasyonu
qemu-img create -f raw sdcard.img 512M
# QCOW2 format — CoW (copy-on-write), sıkıştırma, snapshot desteği
qemu-img create -f qcow2 disk.qcow2 2G
# Image bilgisi görüntüle
qemu-img info sdcard.img
# image: sdcard.img
# file format: raw
# virtual size: 512 MiB (536870912 bytes)
# disk size: 512 MiB
# Raw → QCOW2 dönüştürme
qemu-img convert -f raw -O qcow2 sdcard.img sdcard.qcow2
# NOR flash için sabit boyutlu image (pflash için)
qemu-img create -f raw flash.img 64M
# Boş alanı 0xFF ile doldur (NOR flash varsayılan durumu)
dd if=/dev/zero bs=1M count=64 | tr '\000' '\377' > flash.img
Drive parametreleri
# SD kart — SD/MMC arayüzü üzerinden
qemu-system-arm \
-M virt \
-cpu cortex-a15 \
-drive "file=sdcard.img,format=raw,if=sd" \
-kernel zImage \
-nographic
# SCSI disk — sda olarak görünür
qemu-system-arm \
-M versatilepb \
-drive "file=rootfs.ext2,if=scsi,format=raw" \
-append "root=/dev/sda rw console=ttyAMA0" \
-kernel zImage -nographic
# VirtIO block — yüksek performans, virt makinesiyle kullanılır
qemu-system-aarch64 \
-M virt \
-cpu cortex-a53 \
-drive "file=disk.img,format=raw,if=virtio" \
-append "root=/dev/vda rw console=ttyAMA0" \
-kernel Image -nographic
# NOR Flash (pflash) — U-Boot firmware için
qemu-system-arm \
-M virt \
-drive "file=flash0.img,format=raw,if=pflash" \
-drive "file=flash1.img,format=raw,if=pflash" \
-nographic
-drive seçenekleri özeti
| Parametre | Değerler | Açıklama |
|---|---|---|
file= | dosya yolu | Disk image dosyası |
format= | raw, qcow2, vmdk | Image formatı; raw en basit ve hızlı |
if= | sd, scsi, virtio, pflash, ide, none | Hedef arayüz tipi |
readonly=on | on / off | Read-only montaj — squashfs test için |
cache= | none, writeback, writethrough | I/O cache politikası |
snapshot=on | on / off | Değişiklikleri image'a yazma — geçici çalışma |
Partition oluşturma ve formatlama
# 512 MB image oluştur
qemu-img create -f raw sdcard.img 512M
# Partition tablosu yaz (MBR)
fdisk sdcard.img << 'EOF'
o # MBR partition tablosu oluştur
n # Yeni partition
p # Primary
1 # Partition 1
2048 # Başlangıç sektörü
+64M # Boyut: 64 MB (boot)
t # Tip değiştir
c # W95 FAT32 (LBA)
n # Partition 2
p
2
# varsayılan (FAT sonrası)
# varsayılan (disk sonu)
w # Yaz ve çık
EOF
# Loop device ile bağla ve formatla
sudo losetup -fP sdcard.img
sudo mkfs.vfat -F 32 /dev/loop0p1
sudo mkfs.ext4 /dev/loop0p2
sudo losetup -d /dev/loop0
if=pflash ile NOR flash simüle ederken image boyutu makine tipinin beklediği kapasiteyle tam eşleşmelidir. virt makinesi iki 64 MB pflash sürücü bekler. Boyut uyumsuzluğu QEMU'nun başlamamasına veya U-Boot'un çökmesine yol açar.
Bu bölümde
qemu-img create -f raw sdcard.img 512M: ham disk image oluşturma-drive file=sdcard.img,format=raw,if=sd: SD kart simülasyonu-drive file=flash.img,format=raw,if=pflash: NOR flash (U-Boot için)- VirtIO block (
if=virtio): en yüksek performanslı sanal disk arayüzü
04 Ağ yapılandırması
QEMU'da ağ bağlantısı kurmanın dört yolu: user-mode SLIRP, TAP/bridge, macvlan ve VirtIO — her birinin kullanım senaryosu.
User-mode networking (SLIRP)
SLIRP, root yetkisi gerektirmez. QEMU dahili bir NAT yönlendirici gibi davranır; misafir internete çıkabilir ve host port yönlendirmesiyle misafirdeki servislere erişilebilir. En basit ve en yaygın yöntemdir.
# Basit user-mode (varsayılan — network interface olmadan)
qemu-system-aarch64 \
-M virt -cpu cortex-a53 -m 512M \
-netdev "user,id=net0" \
-device "virtio-net-pci,netdev=net0" \
-kernel Image -nographic
# Port yönlendirme: host:2222 → guest:22 (SSH)
qemu-system-aarch64 \
-M virt -cpu cortex-a53 -m 512M \
-netdev "user,id=net0,hostfwd=tcp::2222-:22" \
-device "virtio-net-pci,netdev=net0" \
-kernel Image -nographic
# Birden fazla port yönlendirme
qemu-system-aarch64 \
-netdev "user,id=net0,\
hostfwd=tcp::2222-:22,\
hostfwd=tcp::8080-:80,\
hostfwd=udp::5353-:53" \
-device "virtio-net-pci,netdev=net0" \
-kernel Image -nographic
# Misafirden host'a SSH bağlantısı
ssh -p 2222 root@localhost
TAP/bridge networking
TAP modu, misafir sistemin fiziksel ağ gibi davranmasını sağlar — host ağındaki diğer makinelerle doğrudan iletişim kurabilir. Root yetkisi gerektirir.
# Gerekli araçlar
sudo apt-get install -y bridge-utils uml-utilities
# Bridge oluştur (eth0 ile br0'ı bağla)
sudo ip link add name br0 type bridge
sudo ip link set br0 up
sudo ip link set eth0 master br0
# TAP interface oluştur
sudo ip tuntap add dev tap0 mode tap user $(whoami)
sudo ip link set tap0 master br0
sudo ip link set tap0 up
# QEMU TAP ile çalıştır
qemu-system-aarch64 \
-M virt -cpu cortex-a53 -m 512M \
-netdev "tap,id=net0,ifname=tap0,script=no,downscript=no" \
-device "virtio-net-pci,netdev=net0,mac=52:54:00:12:34:56" \
-kernel Image -nographic
Network device türleri
| Device | Mimari | Performans | Ne zaman |
|---|---|---|---|
virtio-net-pci | ARM virt, x86 | Yüksek | Modern Linux misafir, virt makinesi |
e1000 | Tüm PCI makineler | Orta | Eski kernel, geniş uyumluluk |
smc91c111 | versatilepb | Düşük | ARM versatilepb makinesi |
lan9118 | Bazı ARM makineler | Orta | SMSC LAN9118 simülasyonu |
CI ortamlarında TAP/bridge kullanmak için Docker container veya VM'in ağ yetenekleri ve root izinleri gerekir. GitHub Actions gibi managed runner'larda user-mode SLIRP ile port yönlendirme pratikte daha kolaydır.
Bu bölümde
- SLIRP (
-netdev user): root gerektirmez, NAT, port yönlendirme ile SSH erişimi hostfwd=tcp::2222-:22: host 2222 → misafir 22 yönlendirme- TAP/bridge: misafir ağ'da tam katılımcı — gerçek IP adresi alır
virtio-net-pci: virt makinesiyle en yüksek ağ performansı
05 Tam embedded boot zinciri
U-Boot + Device Tree + Linux Kernel + Rootfs'in QEMU üzerinde tam boot zinciri — AArch64 virt makinesiyle gerçek embedded sistemin simülasyonu.
Boot zinciri bileşenleri
QEMU -bios u-boot.bin → U-Boot → kernel Image (TFTP/SD) → DTB yükle → kernel boot → rootfs mount → /sbin/init
U-Boot derleme (AArch64 virt)
# Cross-toolchain kur
sudo apt-get install -y gcc-aarch64-linux-gnu
# U-Boot kaynak kodu
git clone https://source.denx.de/u-boot/u-boot.git -b v2024.04
cd u-boot
# QEMU virt AArch64 defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
qemu_arm64_defconfig
# Derle
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
-j$(nproc)
# Çıktı: u-boot.bin (BIOS/ROM image)
ls -lh u-boot.bin
# -rw-r--r-- 1 user user 854K u-boot.bin
Disk image hazırlama
# 1 GB disk image oluştur
qemu-img create -f raw disk.img 1G
# GPT partition tablosu
sgdisk -n 1:2048:+64M -t 1:ef00 \
-n 2:0:0 -t 2:8300 disk.img
# Loop device ile bağla
sudo losetup -fP disk.img
# Örnek: /dev/loop1p1 (boot), /dev/loop1p2 (rootfs)
# Partition formatla
sudo mkfs.vfat -F 32 /dev/loop1p1
sudo mkfs.ext4 /dev/loop1p2
# Boot partition'a kernel ve DTB kopyala
sudo mount /dev/loop1p1 /mnt/boot
sudo cp Image /mnt/boot/
sudo cp qemu-virt.dtb /mnt/boot/
sudo umount /mnt/boot
# Rootfs'i ikinci partition'a yaz
sudo dd if=rootfs.ext4 of=/dev/loop1p2 bs=4M status=progress
sudo losetup -d /dev/loop1
Tam boot komutu
qemu-system-aarch64 \
-M virt \
-cpu cortex-a53 \
-m 1G \
-smp 2 \
-bios u-boot.bin \
-drive "file=disk.img,format=raw,if=none,id=hd0" \
-device "virtio-blk-pci,drive=hd0" \
-netdev "user,id=net0,hostfwd=tcp::2222-:22" \
-device "virtio-net-pci,netdev=net0" \
-serial stdio \
-nographic
# U-Boot'ta autoboot iptal: herhangi bir tuşa bas
# U-Boot prompt'ta:
# => fatload virtio 0:1 ${kernel_addr_r} Image
# => fatload virtio 0:1 ${fdt_addr_r} qemu-virt.dtb
# => booti ${kernel_addr_r} - ${fdt_addr_r}
U-Boot environment — otomatik boot
# U-Boot prompt'ta otomatik boot tanımla
# => setenv bootcmd 'fatload virtio 0:1 ${kernel_addr_r} Image; \
# fatload virtio 0:1 ${fdt_addr_r} qemu-virt.dtb; \
# setenv bootargs "root=/dev/vda2 rw console=ttyAMA0,115200"; \
# booti ${kernel_addr_r} - ${fdt_addr_r}'
# => saveenv
# => boot
Bu bölümde
- U-Boot derleme:
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make qemu_arm64_defconfig -bios u-boot.bin: QEMU U-Boot'u firmware olarak yükler-drive file=disk.img,if=none,id=hd0+-device virtio-blk-pci,drive=hd0: VirtIO disk bağlama- U-Boot
booti: AArch64 kernel Image + DTB yükleme ve boot komutu
06 GDB stub ile debug
QEMU'nun dahili GDB stub'ı ile kernel ve userspace programları kaynak seviyesinde hata ayıklama — -s -S parametreleri ve GDB bağlantısı.
GDB stub aktifleştirme
# -s : GDB stub'ı 1234 portunda dinle (kısayol: -gdb tcp::1234)
# -S : CPU'yu boot'ta dondur (GDB'nin bağlanmasını bekle)
qemu-system-aarch64 \
-M virt \
-cpu cortex-a53 \
-m 512M \
-kernel Image \
-initrd rootfs.cpio.gz \
-append "console=ttyAMA0 rdinit=/sbin/init" \
-serial stdio \
-nographic \
-s -S
# Özel port belirlemek için
qemu-system-aarch64 ... -gdb "tcp::5678"
GDB ile bağlanma (AArch64 kernel)
# AArch64 GDB kur
sudo apt-get install -y gdb-multiarch
# GDB'yi kernel ELF ile başlat (debug sembolleri içermeli)
gdb-multiarch vmlinux
# GDB içinde:
# (gdb) set architecture aarch64
# (gdb) target remote :1234
# Remote debugging using :1234
# 0x0000000040000000 in ?? ()
# Kernel başlangıcına breakpoint
# (gdb) break start_kernel
# Breakpoint 1 at 0xffff800010010000: file init/main.c, line 931
# Çalıştırmaya devam et
# (gdb) continue
# Breakpoint'te durduğunda kaynak görüntüle
# (gdb) list
# (gdb) info registers
# (gdb) x/10i $pc ← PC'deki 10 instruction
Kernel debug sembolleri etkinleştirme
# Linux kaynak dizininde
make ARCH=arm64 menuconfig
# Kernel Hacking bölümünde etkinleştir:
# CONFIG_DEBUG_INFO=y → GDB debug sembolleri
# CONFIG_DEBUG_INFO_DWARF4=y → DWARF 4 format (GDB uyumlu)
# CONFIG_FRAME_POINTER=y → Fonksiyon backtrace desteği
# CONFIG_KGDB=y → Kernel GDB stub (QEMU -s olmadan da çalışır)
# CONFIG_RANDOMIZE_BASE=n → KASLR'ı kapat (sabit adresler için)
# Derle
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)
# vmlinux → debug semboller dahil ELF (GDB'ye verilir)
# arch/arm64/boot/Image → QEMU'ya -kernel ile verilir
QEMU monitor ile bellek inceleme
# Monitor'e geç: Ctrl+A c (nographic modda)
# CPU kayıt dökümü
# (qemu) info registers
# Fiziksel bellekten 10 hex word oku
# (qemu) xp /10xw 0x40200000
# Sanal bellekten oku (CPU 0)
# (qemu) x /10xg 0xffff800010010000
# CPU durumunu görüntüle
# (qemu) info cpus
# Belirli CPU'yu durdur / sürdür
# (qemu) cpu 0
# (qemu) stop
# (qemu) cont
Bu bölümde
-s: GDB stub port 1234;-S: CPU'yu ilk instruction'da dondurgdb-multiarch vmlinux→target remote :1234: AArch64 kernel debugCONFIG_DEBUG_INFO=y + CONFIG_RANDOMIZE_BASE=n: kernel debug için gerekli- QEMU monitor (
xp,x): GDB olmadan fiziksel ve sanal bellek okuma
07 QEMU monitor
QEMU monitor, çalışan sanal makinenin durumunu sorgulama, sistem durumu kaydetme/yükleme ve düşük seviye hata ayıklama için etkileşimli konsoldur.
Monitor'e erişim
-monitor tcp:localhost:4444,server,nowait → nc localhost 4444-monitor unix:/tmp/qemu-monitor.sock,server,nowait → socat - /tmp/qemu-monitor.sockTemel monitor komutları
# Yardım
(qemu) help
(qemu) help info
# CPU kayıtları
(qemu) info registers
# PC=0xffff800010543abc X0=0000000000000001 X1=ffff0000097b2c00 ...
# Bellek okuma
(qemu) xp /10xw 0x40000000 # fiziksel — 10 word hex
(qemu) xp /4xg 0x40000000 # fiziksel — 4 giant (8 byte) hex
(qemu) x /10i 0xffff800010010000 # sanal — 10 instruction disasm
# Cihaz ve IRQ durumu
(qemu) info qtree # cihaz ağacı
(qemu) info irq # IRQ sayaçları
(qemu) info pci # PCI cihazları
(qemu) info block # disk cihazları
(qemu) info network # ağ cihazları
# CPU kontrolü
(qemu) stop # tüm CPU'ları durdur
(qemu) cont # sürdür
(qemu) system_reset # sıcak yeniden başlat
(qemu) system_powerdown # ACPI power-off sinyali gönder
(qemu) quit # QEMU'yu kapat
VM snapshot (savevm / loadvm)
# ÖNEMLİ: snapshot için disk image QCOW2 formatında olmalı
qemu-img create -f qcow2 disk.qcow2 4G
# Sistem çalışırken snapshot al
(qemu) savevm checkpoint1
# Snapshot başarıyla kaydedildi
# Snapshot listesi
(qemu) info snapshots
# ID TAG VM SIZE DATE VM CLOCK
# 1 checkpoint1 154M 2026-01-15 14:23:01 00:01:35.000
# Önceki snapshot'a dön
(qemu) loadvm checkpoint1
# Snapshot sil
(qemu) delvm checkpoint1
# QEMU komut satırından belirli snapshot ile başlat
qemu-system-aarch64 ... -loadvm checkpoint1
QMP (QEMU Machine Protocol)
# QMP üzerinden programatik kontrol
qemu-system-aarch64 \
-M virt -cpu cortex-a53 -m 512M \
-qmp "tcp:localhost:4445,server,nowait" \
-kernel Image -nographic
# QMP ile bağlan
nc localhost 4445
# Handshake: {"execute": "qmp_capabilities"}
# Sistem durdur: {"execute": "stop"}
# CPU bilgisi: {"execute": "query-cpus-fast"}
# Güç kapat: {"execute": "system_powerdown"}
# Snapshot: {"execute": "savevm", "arguments": {"name": "snap1"}}
Bu bölümde
- Monitor erişimi: Ctrl+A c (nographic) veya
-monitor tcp:localhost:4444 info registers,xp /10xw addr: CPU ve bellek incelemesavevm/loadvm: QCOW2 disk üzerinde VM snapshot- QMP: JSON tabanlı programatik makine kontrolü — CI ve otomasyon için
08 Buildroot + QEMU entegrasyonu
Buildroot'un yerleşik QEMU desteği — qemu_arm_versatile_defconfig, otomatik üretilen start-qemu.sh ve CI için kullanımı.
QEMU defconfig'leri
# QEMU için hazır konfigürasyonlar
make list-defconfigs | grep qemu
# qemu_aarch64_virt_defconfig - AArch64 virt makinesi
# qemu_arm_versatile_defconfig - ARM 32-bit versatilepb
# qemu_arm_vexpress_defconfig - ARM Versatile Express
# qemu_mips32r2_malta_defconfig - MIPS32 Malta
# qemu_mips32r2el_malta_defconfig - MIPS32 LE Malta
# qemu_riscv32_virt_defconfig - RISC-V 32-bit
# qemu_riscv64_virt_defconfig - RISC-V 64-bit
# qemu_x86_defconfig - x86 32-bit
# qemu_x86_64_defconfig - x86 64-bit
# AArch64 virt ile build
make qemu_aarch64_virt_defconfig
make -j$(nproc)
start-qemu.sh analizi
#!/bin/sh
# output/images/start-qemu.sh — Buildroot tarafından otomatik üretilir
BINARIES_DIR="${0%/*}/"
cd "${BINARIES_DIR}"
if [ "${1}" = "serial-only" ] ; then
EXTRA_ARGS='-nographic'
else
EXTRA_ARGS=''
fi
# Temel QEMU komutu
exec qemu-system-aarch64 \
-M virt \
-cpu cortex-a53 \
-smp 1 \
-m 1024 \
-kernel Image \
-initrd rootfs.cpio.gz \
-append "rootwait root=/dev/mem console=ttyAMA0,115200" \
-netdev "user,id=net0" \
-device "virtio-net-device,netdev=net0" \
${EXTRA_ARGS}
# Çalıştırma:
# ./start-qemu.sh → grafik mod
# ./start-qemu.sh serial-only → nographic, CI için ideal
Buildroot post-build scripti ile özelleştirme
#!/bin/bash
# BR2_ROOTFS_POST_BUILD_SCRIPT ile çağrılır
TARGET_DIR="$1"
# Basit test scripti rootfs'e ekle
cat > "${TARGET_DIR}/usr/bin/run-tests.sh" << 'TESTEOF'
#!/bin/sh
echo "[TEST] Kernel version: $(uname -r)"
echo "[TEST] CPU info: $(grep 'model name' /proc/cpuinfo | head -1)"
echo "[TEST] Memory: $(free -m | awk '/Mem/{print $2}') MB"
ls /dev/mmcblk0 2>/dev/null && echo "[TEST] SD card: PASS" || echo "[TEST] SD card: SKIP"
echo "[TEST] DONE"
TESTEOF
chmod +x "${TARGET_DIR}/usr/bin/run-tests.sh"
Bu bölümde
- Buildroot: 9 ayrı QEMU defconfig (ARM, AArch64, MIPS, RISC-V, x86)
output/images/start-qemu.sh serial-only: CI için headless boot- post-build.sh ile rootfs'e test scripti enjekte etme
- BR2_ROOTFS_POST_BUILD_SCRIPT: Buildroot build sonrası hook
09 Pratik: CI pipeline'da QEMU
GitHub Actions ve GitLab CI'da cross-compile → QEMU boot → seri çıktıdan pass/fail tespiti — tam otomatik embedded CI pipeline.
Strateji
push → cross-compile (x86-64 host) → QEMU ARM boot → seri çıktı logla → PASS/FAIL → pipeline sonucu
GitHub Actions — ARM QEMU CI
name: Embedded CI — QEMU ARM64
on:
push:
branches: [main, develop]
pull_request:
jobs:
build-and-test:
runs-on: ubuntu-22.04
steps:
# 1. Bağımlılıklar
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
gcc-aarch64-linux-gnu \
qemu-system-aarch64 \
expect
# 2. Kaynak kodu kontrol et
- uses: actions/checkout@v4
# 3. Cross-compile
- name: Cross-compile application
run: |
aarch64-linux-gnu-gcc \
-static -O2 \
-o app_arm64 \
src/main.c
aarch64-linux-gnu-strip app_arm64
# 4. Kernel + rootfs indir (önceden derlenmiş)
- name: Download test rootfs
run: |
wget -q https://example.com/ci/rootfs-aarch64.cpio.gz
wget -q https://example.com/ci/Image-aarch64
# 5. App'ı rootfs'e enjekte et
- name: Inject app into rootfs
run: |
mkdir -p rootfs_inject/usr/bin
cp app_arm64 rootfs_inject/usr/bin/app
cat > rootfs_inject/etc/init.d/S99test << 'EOF'
#!/bin/sh
/usr/bin/app && echo "APP_TEST_PASS" || echo "APP_TEST_FAIL"
poweroff -f
EOF
chmod +x rootfs_inject/etc/init.d/S99test
cd rootfs_inject
find . | cpio -H newc -o | gzip -9 > ../app-rootfs.cpio.gz
# 6. QEMU boot + çıktı yakala
- name: Boot and test
run: |
timeout 120 qemu-system-aarch64 \
-M virt \
-cpu cortex-a53 \
-m 512M \
-smp 2 \
-kernel Image-aarch64 \
-initrd app-rootfs.cpio.gz \
-append "console=ttyAMA0 rdinit=/sbin/init" \
-serial file:serial.log \
-nographic || true
cat serial.log
grep -q "APP_TEST_PASS" serial.log && \
echo "TEST PASSED" || \
(echo "TEST FAILED"; exit 1)
GitLab CI — YAML
stages:
- build
- test
variables:
CROSS: "aarch64-linux-gnu-"
ARCH: "arm64"
build:arm64:
stage: build
image: ubuntu:22.04
before_script:
- apt-get update -qq
- apt-get install -y -qq gcc-aarch64-linux-gnu make
script:
- make CROSS_COMPILE=${CROSS} ARCH=${ARCH} all
artifacts:
paths: [build/app_arm64]
expire_in: 1 hour
test:qemu-aarch64:
stage: test
image: ubuntu:22.04
dependencies: [build:arm64]
before_script:
- apt-get update -qq
- apt-get install -y -qq qemu-system-aarch64
script:
- |
timeout 120 qemu-system-aarch64 \
-M virt -cpu cortex-a53 -m 512M \
-kernel ${CI_PROJECT_DIR}/ci/Image \
-initrd ${CI_PROJECT_DIR}/ci/rootfs.cpio.gz \
-append "console=ttyAMA0 rdinit=/sbin/init" \
-serial file:qemu.log -nographic || true
grep -q "TESTS_PASSED" qemu.log
artifacts:
paths: [qemu.log]
when: always
Expect ile interaktif test
#!/usr/bin/expect -f
# test-qemu.exp — login + komut çalıştır + sonucu doğrula
set timeout 120
# QEMU'yu başlat
spawn qemu-system-aarch64 \
-M virt -cpu cortex-a53 -m 512M \
-kernel Image -initrd rootfs.cpio.gz \
-append "console=ttyAMA0 rdinit=/sbin/init" \
-nographic
# Login prompt'u bekle
expect "login:"
send "root\r"
# Shell prompt'u bekle
expect "# "
# Uygulamayı çalıştır
send "/usr/bin/app --test\r"
# Başarı çıktısını bekle (60 saniye içinde)
expect {
"TEST_OK" { puts "PASS"; exit 0 }
"TEST_FAIL" { puts "FAIL"; exit 1 }
timeout { puts "TIMEOUT"; exit 2 }
}
CI'da QEMU timeout değerini dikkatli ayarlayın. Boot + init + test süresi genellikle 30–60 saniye arasındadır. timeout 120 ile 2 dakika üst sınırı güvenli bir başlangıç noktasıdır. Yavaş disk I/O gerektiren testler için bu süreyi artırın.
GitHub Actions shared runner'larında KVM desteği yoktur — TCG modu kullanılır. ARM64 emülasyonu x86-64 native çalışmaya göre 5–15x yavaştır. Uzun çalışan testler için self-hosted runner veya ARM runner tercih edin. Test süresini minimize etmek için rootfs'i küçük tutun ve gereksiz init servislerini devre dışı bırakın.
Bu bölümde
- GitHub Actions: cross-compile + rootfs enjekte + QEMU boot + serial.log grep ile pass/fail
- GitLab CI: iki aşamalı pipeline — build artifact → test job
expect: interaktif login + komut çalıştırma + çıktı doğrulama- TCG'de ARM64 emülasyonu 5–15x yavaş — timeout ve rootfs boyutunu buna göre ayarla