9.2 KiB
QEMU UEFI Testing Guide
This guide covers testing MetalOS in QEMU with UEFI firmware (OVMF).
Overview
MetalOS uses QEMU with OVMF (Open Virtual Machine Firmware) to test UEFI boot functionality without requiring physical hardware. This enables rapid development and testing of the bootloader and kernel.
Prerequisites
Required Software
-
QEMU (version 6.0 or later recommended)
- Provides x86_64 virtualization
- Supports UEFI firmware
-
OVMF (UEFI firmware for QEMU)
- Open-source UEFI implementation
- Required for UEFI boot in QEMU
-
mtools (for disk image creation)
- Creates FAT32 filesystems
- Manipulates MS-DOS filesystems
Installation
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install qemu-system-x86 ovmf mtools xorriso
Arch Linux:
sudo pacman -S qemu-full edk2-ovmf mtools xorriso
Fedora:
sudo dnf install qemu-system-x86 edk2-ovmf mtools xorriso
macOS:
brew install qemu mtools xorriso
# Note: OVMF may need manual installation
Quick Start
Basic QEMU Boot
# Build and boot MetalOS in QEMU
make qemu
This command:
- Builds the bootloader and kernel (or uses placeholders)
- Creates a FAT32 disk image with UEFI boot structure
- Launches QEMU with OVMF firmware
- Boots the system in headless mode
Expected Output:
Building bootloader...
Building kernel...
Creating bootable image...
Using mtools to create FAT32 disk image...
Success! Created build/metalos.img
Starting QEMU with UEFI firmware...
Using OVMF firmware: /usr/share/ovmf/OVMF.fd
Display mode: none (set QEMU_DISPLAY=gtk for graphical)
[UEFI boot messages...]
Verify UEFI Setup
To verify that QEMU and OVMF are properly installed:
make qemu-uefi-test
This boots directly to the UEFI shell without any OS image, confirming your setup works.
Display Modes
MetalOS supports multiple display modes for different use cases:
Headless Mode (Default)
make qemu
# or explicitly
make qemu QEMU_DISPLAY=none
Use cases:
- CI/CD pipelines
- Headless servers
- Automated testing
- Serial console debugging
Characteristics:
- No graphical window
- Serial output only
- Works in any environment
Graphical Mode - GTK
make qemu QEMU_DISPLAY=gtk
Use cases:
- Interactive development
- Visual debugging
- UI testing
Characteristics:
- Native GTK window
- Full graphics support
- Requires X11/Wayland
Graphical Mode - SDL
make qemu QEMU_DISPLAY=sdl
Use cases:
- Cross-platform development
- Alternative to GTK
Characteristics:
- SDL window
- Good compatibility
- Lighter than GTK
Text Mode - Curses
make qemu QEMU_DISPLAY=curses
Use cases:
- SSH sessions
- Text-only environments
Characteristics:
- Terminal-based UI
- No X11 required
- Works over SSH
Advanced Testing
Debug Mode
Boot with CPU interrupt and reset debugging:
make qemu-debug
Additional debug output includes:
- CPU interrupts
- CPU resets
- Exception handling
- Hardware events
GDB Debugging
Debug the kernel with GDB:
Terminal 1 - Start QEMU with GDB server:
make qemu-gdb
QEMU will wait for GDB connection on localhost:1234.
Terminal 2 - Connect GDB:
gdb kernel/metalos.bin
(gdb) target remote localhost:1234
(gdb) break kernel_main
(gdb) continue
Useful GDB commands:
# Set breakpoints
break *0x100000 # Break at address
break kernel_main # Break at function
# Examine memory
x/10i $rip # Disassemble 10 instructions
x/10x 0x100000 # Show 10 hex values
# Step through code
stepi # Step one instruction
nexti # Step over calls
continue # Continue execution
# Register inspection
info registers # Show all registers
print $rax # Print specific register
Disk Image Details
Image Structure
The build/metalos.img file contains:
metalos.img (64 MB FAT32 disk)
├── EFI/
│ └── BOOT/
│ └── bootx64.efi # UEFI bootloader
└── metalos.bin # Kernel binary
Inspecting the Image
View the disk image contents:
# List files in the image
mdir -i build/metalos.img ::/
# List EFI boot directory
mdir -i build/metalos.img ::/EFI/BOOT/
# Extract a file
mcopy -i build/metalos.img ::/metalos.bin extracted_kernel.bin
# Get image info
file build/metalos.img
Manual Image Creation
If you need to manually create or modify the image:
# Create empty 64MB image
dd if=/dev/zero of=disk.img bs=1M count=64
# Format as FAT32
mformat -i disk.img -F -v "METALOS" ::
# Create directory structure
mmd -i disk.img ::/EFI
mmd -i disk.img ::/EFI/BOOT
# Copy files
mcopy -i disk.img bootloader/bootx64.efi ::/EFI/BOOT/
mcopy -i disk.img kernel/metalos.bin ::/
OVMF Firmware
Firmware Locations
The Makefile automatically detects OVMF firmware in these locations:
/usr/share/OVMF/OVMF_CODE.fd(Ubuntu/Debian)/usr/share/ovmf/OVMF.fd(Ubuntu/Debian alternative)/usr/share/edk2-ovmf/x64/OVMF_CODE.fd(Arch Linux)/usr/share/qemu/ovmf-x86_64.bin(Other systems)
Firmware Variants
OVMF_CODE.fd: Code-only firmware (read-only)
- Used with
-drive if=pflash,readonly=on - Best for testing
- Variables stored separately
OVMF.fd: Combined code and variables
- Single file for firmware
- Simpler setup
- Variables reset on each boot
OVMF.secboot.fd: Secure Boot enabled
- For secure boot testing
- Requires signed bootloader
Troubleshooting
QEMU Won't Start
Issue: gtk initialization failed or Could not initialize SDL
Solution: Use headless mode:
make qemu QEMU_DISPLAY=none
OVMF Not Found
Issue: Error: OVMF UEFI firmware not found!
Solution: Install OVMF package:
# Ubuntu/Debian
sudo apt-get install ovmf
# Arch Linux
sudo pacman -S edk2-ovmf
Image Creation Fails
Issue: mformat: command not found
Solution: Install mtools:
# Ubuntu/Debian
sudo apt-get install mtools
# Arch Linux
sudo pacman -S mtools
Boots to UEFI Shell
Expected Behavior: During development, booting to UEFI shell is normal until the bootloader is complete.
What it means:
- ✅ QEMU and OVMF working correctly
- ✅ Disk image recognized (shows as FS0)
- ⚠️ Bootloader not yet functional (expected in Phase 1)
Next steps: Implement Phase 2 (UEFI Bootloader)
Serial Output Missing
Issue: No serial console output
Solution: Ensure serial port is configured correctly:
- Output goes to stdio by default
- Check that
-serial stdiois in QEMU command - Verify kernel writes to serial port
QEMU Hangs
Issue: QEMU appears to hang during boot
Possible causes:
- Bootloader infinite loop
- Waiting for input
- Hardware initialization issue
Debug steps:
# Use debug mode
make qemu-debug
# Use GDB to inspect state
make qemu-gdb
# In another terminal: gdb kernel/metalos.bin
CI/CD Integration
GitHub Actions
Example workflow for QEMU testing:
name: QEMU Boot Test
on: [push, pull_request]
jobs:
qemu-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y qemu-system-x86 ovmf mtools
- name: Build and test in QEMU
run: |
make qemu QEMU_DISPLAY=none &
QEMU_PID=$!
sleep 10
kill $QEMU_PID || true
Docker Testing
Run QEMU tests in Docker:
FROM ubuntu:latest
RUN apt-get update && apt-get install -y \
build-essential nasm qemu-system-x86 ovmf mtools
WORKDIR /metalos
COPY . .
CMD ["make", "qemu", "QEMU_DISPLAY=none"]
Performance Tuning
Memory Allocation
Default: 512 MB
Adjust memory:
# Edit Makefile QEMU command
qemu-system-x86_64 ... -m 1024M # Use 1GB
CPU Configuration
Use multiple cores:
qemu-system-x86_64 ... -smp 2 # 2 cores
KVM Acceleration
Enable KVM for faster emulation (Linux only):
qemu-system-x86_64 ... -enable-kvm
Note: Requires KVM kernel module and permissions.
Best Practices
- Always test in headless mode first - Ensures CI/CD compatibility
- Use serial output for debugging - More reliable than graphics
- Keep disk images small - 64 MB is sufficient for development
- Test with different OVMF versions - Ensures compatibility
- Document boot behavior changes - Track progress in commits
- Use GDB for serious debugging - More powerful than printf
- Test on multiple systems - Catch compatibility issues early
Resources
Related Documentation
- BUILD.md - Build system and toolchain
- TESTING.md - Complete testing guide
- ROADMAP.md - Development phases
- DEVELOPMENT.md - Development workflow