Project 11: Virtual Machine Boot Process Inspector
Master the art of VM boot analysis by dissecting QEMU’s firmware emulation, comparing SeaBIOS and OVMF boot paths, and creating professional technical documentation that reveals how virtualization layers construct the illusion of real hardware initialization.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Advanced |
| Time Estimate | 1-2 weeks |
| Language | C + Shell scripting (primary), Python (for analysis scripts) |
| Prerequisites | Projects 1-3, GDB familiarity, basic understanding of x86 boot process |
| Key Topics | QEMU debug flags, GDB remote debugging, SeaBIOS internals, OVMF/UEFI architecture, virtualization layers, technical documentation |
1. Learning Objectives
By completing this project, you will:
- Master QEMU’s debugging infrastructure: Use
-dflags effectively to trace execution, interrupts, and CPU state changes throughout the boot process - Attach GDB to VM boot sequences: Set breakpoints at critical addresses (0xFFFF0, 0x7C00), inspect registers, and trace code execution in real mode, protected mode, and long mode
- Understand SeaBIOS architecture: Trace how this open-source BIOS implementation performs POST, device initialization, and boot device selection
- Analyze OVMF/EDK2 boot phases: Follow the SEC, PEI, DXE, BDS, and RT phases of UEFI firmware implementation in virtual machines
- Compare virtualization strategies: Distinguish between full emulation, paravirtualization, and passthrough approaches in QEMU/KVM
- Create professional technical documentation: Produce timeline diagrams, comparison tables, and reproducible analysis workflows
- Develop systematic debugging methodology: Apply structured approaches to investigate complex system initialization sequences
2. Theoretical Foundation
2.1 Core Concepts
Virtual machines are the perfect bootloader laboratory. Unlike physical hardware where you’re blind to internal state, VMs let you pause at any instruction, inspect all memory, and watch the entire boot process step-by-step. Understanding how hypervisors emulate firmware and hardware initialization reveals both bootloader mechanics AND virtualization architecture.
Physical vs Virtual Boot: What You Can See
PHYSICAL HARDWARE VIRTUAL MACHINE (QEMU)
┌──────────────────────────┐ ┌──────────────────────────┐
│ │ │ │
│ CPU executes at │ │ QEMU process runs │
│ full speed │ │ on host CPU │
│ │ │ │ │ │
│ │ (invisible) │ │ │ (observable) │
│ ▼ │ │ ▼ │
│ ┌──────────────┐ │ │ ┌──────────────┐ │
│ │ Firmware ROM │ │ │ │ Firmware │ │
│ │ (proprietary │ │ │ │ (SeaBIOS/ │ │
│ │ closed-source) │ │ │ OVMF source │ │
│ └──────────────┘ │ │ │ available!) │ │
│ │ │ │ └──────────────┘ │
│ │ (can only │ │ │ │
│ │ see POST │ │ │ -d in_asm │
│ │ messages) │ │ │ shows every │
│ ▼ │ │ │ instruction! │
│ ┌──────────────┐ │ │ ▼ │
│ │ Bootloader │ │ │ ┌──────────────┐ │
│ └──────────────┘ │ │ │ Bootloader │ │
│ │ │ │ └──────────────┘ │
│ │ (need JTAG │ │ │ │
│ │ debugger) │ │ │ GDB attached │
│ ▼ │ │ │ via -s -S │
│ ┌──────────────┐ │ │ ▼ │
│ │ OS │ │ │ ┌──────────────┐ │
│ └──────────────┘ │ │ │ OS │ │
│ │ │ └──────────────┘ │
│ Limited visibility │ │ │
│ without special tools │ │ COMPLETE VISIBILITY │
│ │ │ at every level │
└──────────────────────────┘ └──────────────────────────┘
2.2 QEMU/KVM Architecture Stack
Understanding the virtualization stack is essential for interpreting debug output:
QEMU/KVM Architecture: Who Does What
┌─────────────────────────────────────────────────────────────────────────────┐
│ USER SPACE │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ QEMU PROCESS │ │
│ │ │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ Virtual Machine │ │ Device │ │ Firmware │ │ │
│ │ │ Monitor (QMP) │ │ Emulation │ │ Loading │ │ │
│ │ │ - VM control │ │ - IDE/AHCI │ │ - SeaBIOS │ │ │
│ │ │ - Debug output │ │ - VGA/virtio-gpu│ │ - OVMF │ │ │
│ │ │ - -d flags │ │ - NIC (e1000, │ │ - Custom BIOS │ │ │
│ │ └──────────────────┘ │ virtio-net) │ └──────────────────┘ │ │
│ │ │ - USB, Sound │ │ │
│ │ ┌──────────────────┐ └──────────────────┘ │ │
│ │ │ GDB Server │ │ │
│ │ │ (port 1234) │ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ - -s -S flags │ │ Memory │ │ vCPU Thread(s) │ │ │
│ │ │ - Remote debug │ │ Management │ │ - Execute guest │ │ │
│ │ └──────────────────┘ │ - Guest RAM │ │ code │ │ │
│ │ │ - MMIO regions │ │ - Handle exits │ │ │
│ │ └──────────────────┘ └────────┬─────────┘ │ │
│ │ │ │ │
│ └───────────────────────────────────────────────────────┼──────────────┘ │
│ │ │
│ ioctl(KVM_RUN) │ │
│ ▼ │
└──────────────────────────────────────────────────────────┼───────────────────┘
│
┌──────────────────────────────────────────────────────────┼───────────────────┐
│ KERNEL SPACE │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ KVM MODULE (/dev/kvm) │ │
│ │ │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ VM Creation │ │ vCPU Management │ │ Memory Mapping │ │ │
│ │ │ - ioctl calls │ │ - VMCS setup │ │ - EPT/NPT │ │ │
│ │ │ - Resource │ │ - VMENTER │ │ - Guest phys→ │ │ │
│ │ │ allocation │ │ - VMEXIT │ │ Host virt │ │ │
│ │ │ │ │ - State save │ │ │ │ │
│ │ └──────────────────┘ └────────┬─────────┘ └──────────────────┘ │ │
│ │ │ │ │
│ └─────────────────────────────────┼────────────────────────────────────┘ │
│ │ │
│ Hardware Virtualization Extensions │
│ │ │
└────────────────────────────────────┼─────────────────────────────────────────┘
│
┌────────────────────────────────────┼─────────────────────────────────────────┐
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ CPU HARDWARE │ │
│ │ │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ Intel VT-x │ │ AMD-V (SVM) │ │ Without HW Virt │ │ │
│ │ │ - VMCS │ │ - VMCB │ │ - TCG emulation │ │ │
│ │ │ - Non-root mode │ │ - Guest mode │ │ - Very slow │ │ │
│ │ │ - EPT │ │ - NPT │ │ - All software │ │ │
│ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ │ │
│ │ │ │
│ │ Guest code runs at near-native speed when KVM is available! │ │
│ │ Without KVM, QEMU uses TCG (Tiny Code Generator) for emulation │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ PHYSICAL CPU │
└──────────────────────────────────────────────────────────────────────────────┘
2.3 SeaBIOS vs OVMF: Architectural Comparison
These are the two main firmware implementations used in QEMU:
SeaBIOS vs OVMF: Boot Flow Comparison
SeaBIOS (Legacy BIOS) OVMF (UEFI)
===================== ===========
Start Address: 0xFFFF:FFF0 (reset vector) 0xFFFF:FFF0 (same reset)
Far JMP to 0xF000:xxxx Far JMP to PEI entry
Execution Mode: Real Mode (16-bit) 32-bit Protected Mode
Initial Phase: ───────────────────── ─────────────────────
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ POST │ │ SEC Phase │
│ - Memory detection │ │ - Security/Reset │
│ - CPU initialization │ │ - Temporary RAM init │
│ - Timer setup │ │ - Find PEI core │
│ - ~50-100ms │ │ - ~50-100ms │
└───────────┬─────────────┘ └───────────┬─────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ Option ROM Scan │ │ PEI Phase │
│ - VGA BIOS │ │ - Pre-EFI Init │
│ - Network boot ROM │ │ - Memory reference │
│ - SCSI/RAID cards │ │ code (MRC) │
│ - ~50-200ms │ │ - Find DXE core │
└───────────┬─────────────┘ │ - ~200-500ms │
│ └───────────┬─────────────┘
│ │
│ ▼
│ ┌─────────────────────────┐
│ │ DXE Phase │
│ │ - Driver Execution │
│ │ - Protocol database │
│ │ - ACPI tables │
│ │ - ~300-800ms │
│ └───────────┬─────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ INT 19h Boot │ │ BDS Phase │
│ - Check boot devices │ │ - Boot Device Select │
│ - Read MBR (sector 0) │ │ - Find EFI apps │
│ - Validate 0xAA55 │ │ - Boot menu │
│ - Load to 0x7C00 │ │ - Load from ESP │
└───────────┬─────────────┘ └───────────┬─────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ Bootloader Exec │ │ EFI Application │
│ - JMP 0x0000:7C00 │ │ - PE32+ executable │
│ - Bootloader takes │ │ - Has UEFI services │
│ control │ │ - Can be Secure Boot │
│ │ │ verified │
└───────────┬─────────────┘ └───────────┬─────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ OPERATING SYSTEM │
└─────────────────────────────────────────────────────────────────┘
Total Boot Time: ~100-200ms (emulated) ~1-3s (emulated)
(to bootloader) ~20-50ms (KVM accelerated) ~200-500ms (KVM accelerated)
Interface: INT-based services Function pointer tables
(INT 10h video, INT 13h disk) (Boot Services, Runtime Services)
Boot Target: MBR-partitioned disk GPT-partitioned disk
Boot sector at 0x7C00 FAT32 ESP, PE32+ binary
Security: None built-in Secure Boot, TPM integration
2.4 QEMU Debug Infrastructure
Understanding the debugging tools available:
QEMU Debug Flag Categories
┌─────────────────────────────────────────────────────────────────────────────┐
│ QEMU DEBUG FLAGS (-d) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ EXECUTION TRACING CPU STATE │
│ ────────────────── ───────── │
│ -d in_asm Every guest -d cpu CPU state at │
│ instruction translation time │
│ (VERY verbose!) │
│ -d cpu_reset CPU state at reset │
│ -d exec Translation blocks │
│ executed │
│ EXCEPTIONS & INTERRUPTS │
│ -d op Micro-ops from ─────────────────────── │
│ TCG -d int All interrupts │
│ (INT 10h, 13h, etc.) │
│ -d op_opt Optimized micro-ops │
│ -d pcall Protected mode calls │
│ │
│ MEMORY ACCESS DEVICE EMULATION │
│ ───────────── ──────────────── │
│ -d mmu MMU/TLB changes -d ioport I/O port access │
│ │
│ -d page Page table changes -d guest_errors Invalid guest ops │
│ │
│ -d unimp Unimplemented COMBINING FLAGS │
│ features accessed ─────────────── │
│ -d int,cpu_reset │
│ -d int,in_asm,ioport │
│ -d help (list all flags) │
│ │
│ OUTPUT CONTROL │
│ ────────────── │
│ -D filename Write debug output to file (required for large traces!) │
│ -dfilter Filter by address range │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Example Commands for Boot Analysis:
# Minimal (boot phases only)
qemu-system-x86_64 -d cpu_reset -D reset.log -hda disk.img -nographic
# Interrupt tracing (firmware services)
qemu-system-x86_64 -d int -D interrupts.log -hda disk.img -nographic
# Full trace (WARNING: generates GB of data!)
qemu-system-x86_64 -d in_asm,int -D full_trace.log -hda disk.img | head -100000
# OVMF with variable storage
qemu-system-x86_64 -bios OVMF_CODE.fd \
-drive if=pflash,format=raw,file=OVMF_VARS.fd \
-d int,cpu_reset -D ovmf.log -hda disk.img
2.5 Memory Layout During Boot
Understanding where things live in memory:
x86 Memory Map During SeaBIOS Boot
0x00000000 ┌────────────────────────────────────────────────────────┐
│ Interrupt Vector Table (IVT) │
│ 256 entries x 4 bytes = 1KB │
│ INT 00h at 0x0000, INT 01h at 0x0004, etc. │
0x00000400 ├────────────────────────────────────────────────────────┤
│ BIOS Data Area (BDA) │
│ - COM/LPT port addresses │
│ - Equipment list │
│ - Memory size │
│ - Keyboard buffer │
│ - Video mode │
0x00000500 ├────────────────────────────────────────────────────────┤
│ Free conventional memory │
│ (Available for bootloader use) │
│ │
0x00007C00 ├───────────────── BOOTLOADER LOADS HERE ────────────────┤
│ Boot sector (512 bytes) │
│ 0x7C00-0x7DFF │
0x00007E00 ├────────────────────────────────────────────────────────┤
│ Free (typically used for second stage) │
│ │
│ │
0x0009FC00 ├────────────────────────────────────────────────────────┤
│ Extended BIOS Data Area (EBDA) │
│ ~1KB, location varies │
0x000A0000 ├────────────────────────────────────────────────────────┤
│ Video Memory │
│ VGA framebuffer, text mode at 0xB8000 │
0x000C0000 ├────────────────────────────────────────────────────────┤
│ Video BIOS ROM │
│ (copied/mapped from expansion card) │
0x000C8000 ├────────────────────────────────────────────────────────┤
│ Other Option ROMs │
│ (Network boot, SCSI, RAID) │
0x000F0000 ├────────────────────────────────────────────────────────┤
│ SeaBIOS Code │
│ System BIOS area │
│ INT handlers, POST code, boot logic │
0x00100000 ├───────────────── 1MB BOUNDARY ─────────────────────────┤
│ Extended Memory (if A20 enabled) │
│ OS loads here │
│ │
Reset Vector (where CPU starts):
0xFFFF0 ────┬──────────────────────────────────────────────────────┐
│ JMP F000:E05B (jump to SeaBIOS initialization) │
│ This is in the top 64KB of the 1MB address space │
└──────────────────────────────────────────────────────┘
Note: CPU starts at 0xFFFFFFF0 in modern processors (4GB - 16 bytes)
but segment:offset addressing in real mode wraps to 0xFFFF0
2.6 Why This Matters
Industry Applications:
- Cloud Infrastructure: AWS, GCP, Azure use QEMU/KVM extensively. Understanding VM boot is crucial for cloud engineering roles
- Firmware Development: Testing BIOS/UEFI implementations without physical hardware
- Security Research: Analyzing boot-time attacks, rootkits, and Secure Boot bypasses
- Embedded Development: Using QEMU to develop and test before hardware is available
- DevOps: Debugging VM provisioning failures, understanding cloud-init execution timing
Career Impact:
- Deep virtualization knowledge sets you apart in SRE/infrastructure roles
- VM boot debugging skills are invaluable for troubleshooting production issues
- Understanding firmware is essential for security roles
2.7 Common Misconceptions
Misconception 1: “QEMU always uses KVM”
- Reality: QEMU can run in pure emulation mode (TCG) without KVM. KVM requires hardware virtualization support (VT-x/AMD-V) and only accelerates CPU execution. Device emulation is always done by QEMU userspace code.
Misconception 2: “SeaBIOS and OVMF boot the same way”
- Reality: SeaBIOS boots in real mode using INT services, loads MBR to 0x7C00. OVMF boots in protected mode, uses function pointer tables, loads PE32+ executables from EFI System Partition.
Misconception 3: “Debug logging slows down the VM significantly”
- Reality: Minimal logging (
-d cpu_reset) has negligible impact. Full instruction tracing (-d in_asm) can slow boot by 100x+ and generate gigabytes of log data.
Misconception 4: “BIOS and UEFI are interchangeable”
- Reality: They’re fundamentally different architectures. A BIOS bootloader won’t work in UEFI mode. A UEFI application won’t run on legacy BIOS. Some systems support both (CSM mode), but they require different boot code.
3. Project Specification
3.1 What You Will Build
A comprehensive investigation and documentation of how QEMU boots virtual machines, including:
- Boot Tracing Environment: Scripts and configurations for capturing detailed boot sequences
- GDB Debugging Setup: Automated scripts for attaching to boot at critical points
- SeaBIOS Analysis Document: Detailed breakdown of legacy BIOS boot process in QEMU
- OVMF Analysis Document: Comprehensive analysis of UEFI boot phases
- Comparison Report: Side-by-side analysis of SeaBIOS vs OVMF
- Timeline Diagrams: Visual representations of boot sequences with timing data
- Reproducibility Package: Scripts allowing others to recreate your analysis
3.2 Functional Requirements
| Requirement | Description | Verification |
|---|---|---|
| FR1: Debug Logging | Capture boot logs using QEMU -d flags | Log files contain interrupt and execution traces |
| FR2: GDB Integration | Attach GDB to VM and set breakpoints at boot | Breakpoint at 0x7C00 triggers, registers inspectable |
| FR3: SeaBIOS Trace | Document complete SeaBIOS boot sequence | Timeline from reset to 0x7C00 with all INT calls |
| FR4: OVMF Trace | Document complete OVMF boot sequence | All 5 phases identified with timing data |
| FR5: Comparison | Produce SeaBIOS vs OVMF comparison table | Metrics compared: time, memory, INT usage, complexity |
| FR6: Reproducibility | Package allows others to reproduce analysis | Another person can run scripts and get similar results |
3.3 Non-Functional Requirements
| Requirement | Description |
|---|---|
| NFR1 | Analysis completed for both SeaBIOS and OVMF |
| NFR2 | Documentation suitable for technical audience (junior to senior engineers) |
| NFR3 | All scripts work on Linux (Ubuntu 20.04+) |
| NFR4 | Total documentation under 50 pages, focused and concise |
3.4 Example Output
# Trace boot execution:
$ ./trace_boot.sh seabios disk.img
[*] Starting QEMU with SeaBIOS, debug logging enabled...
[*] Log file: logs/seabios_20240115_143022.log
[*] Boot completed, analyzing...
=== SEABIOS BOOT ANALYSIS ===
Reset vector accessed at: 0xFFFF0
First instruction: JMP F000:E05B
POST started: +0.2ms
Memory detection: +2.1ms
PCI enumeration: +15.3ms
VGA initialization: +22.7ms
Boot device search: +45.8ms
MBR read (INT 13h): +48.2ms
Jump to 0x7C00: +50.1ms
Total boot time: 50.1ms
INT 13h calls: 12
INT 10h calls: 47
INT 16h calls: 2
# Attach GDB at boot:
$ ./gdb_boot.sh disk.img
[*] Starting QEMU with GDB server (-s -S)...
[*] Launching GDB with boot_debug.gdb script...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
(gdb) set arch i8086
The target architecture is set to "i8086".
(gdb) break *0x7c00
Breakpoint 1 at 0x7c00
(gdb) continue
Continuing.
Breakpoint 1, 0x00007c00 in ?? ()
(gdb) x/10i $pc
0x7c00: cli
0x7c01: xor %ax,%ax
0x7c03: mov %ax,%ds
0x7c05: mov %ax,%es
0x7c07: mov %ax,%ss
0x7c09: mov $0x7c00,%sp
...
# Your documentation includes:
- Timeline diagram from power-on to OS
- Comparison table: SeaBIOS vs OVMF
- Analysis of what QEMU virtualizes vs emulates
- Annotated GDB session transcripts
3.5 Real World Outcome
Upon completion, you’ll have:
- A definitive reference document for how VMs boot
- Skills directly applicable to cloud infrastructure debugging
- Deep understanding of both BIOS and UEFI architectures
- Professional-quality technical documentation for your portfolio
- Reproducible analysis methodology applicable to other systems
4. Solution Architecture
4.1 High-Level Design
Analysis Environment Architecture
┌─────────────────────────────────────────────────────────────────────────────┐
│ DEVELOPMENT MACHINE │
│ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ SCRIPTS DIRECTORY │ │
│ │ │ │
│ │ trace_boot.sh gdb_boot.sh analyze_logs.py │ │
│ │ ├─ Start QEMU ├─ Start QEMU ├─ Parse log files │ │
│ │ ├─ Configure -d flags │ with -s -S ├─ Extract events │ │
│ │ ├─ Save logs ├─ Launch GDB ├─ Generate timelines │ │
│ │ └─ Basic analysis └─ Load debug script └─ Compare firmware │ │
│ │ │ │
│ │ boot_debug.gdb compare.sh generate_report.sh │ │
│ │ ├─ Set architecture ├─ Run both ├─ Combine all │ │
│ │ ├─ Connect to QEMU │ SeaBIOS & OVMF │ analysis outputs │ │
│ │ ├─ Set breakpoints ├─ Compare metrics ├─ Generate markdown │ │
│ │ └─ Log commands └─ Output table └─ Create diagrams │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ QEMU INSTANCES │ │
│ │ │ │
│ │ ┌─────────────────────────┐ ┌─────────────────────────────────┐ │ │
│ │ │ SeaBIOS Boot │ │ OVMF Boot │ │ │
│ │ │ │ │ │ │ │
│ │ │ qemu-system-x86_64 │ │ qemu-system-x86_64 │ │ │
│ │ │ -M pc │ │ -M q35 │ │ │
│ │ │ -d int,cpu_reset │ │ -bios OVMF_CODE.fd │ │ │
│ │ │ -D seabios.log │ │ -drive if=pflash,format=raw, │ │ │
│ │ │ -s -S (for GDB) │ │ file=OVMF_VARS.fd │ │ │
│ │ │ -hda disk.img │ │ -d int,cpu_reset │ │ │
│ │ │ │ │ -D ovmf.log │ │ │
│ │ │ Uses built-in SeaBIOS │ │ -hda disk.img │ │ │
│ │ └─────────────────────────┘ │ │ │ │
│ │ │ Full UEFI implementation │ │ │
│ │ └─────────────────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────────┐ │
│ │ OUTPUT FILES │ │
│ │ │ │
│ │ logs/ docs/ diagrams/ │ │
│ │ ├─ seabios_*.log ├─ SEABIOS_ANALYSIS.md ├─ boot_timeline.png│ │
│ │ ├─ ovmf_*.log ├─ OVMF_ANALYSIS.md ├─ memory_layout.png│ │
│ │ ├─ gdb_session.txt ├─ COMPARISON.md └─ architecture.png │ │
│ │ └─ parsed_events.json └─ METHODOLOGY.md │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
4.2 Key Components
| Component | Description | Location |
|---|---|---|
| Test Disk Image | Simple bootloader to test against | images/test_disk.img |
| Tracing Scripts | Shell scripts to launch QEMU with debug flags | scripts/trace_*.sh |
| GDB Scripts | Automated debugging for boot analysis | scripts/boot_debug.gdb |
| Log Parsers | Python scripts to analyze debug output | scripts/analyze_*.py |
| Documentation | Markdown files with analysis results | docs/ |
| Firmware Binaries | OVMF firmware for UEFI testing | firmware/OVMF_*.fd |
4.3 Analysis Workflow
Analysis Workflow: From Boot to Documentation
Phase 1: ENVIRONMENT SETUP
│
├─► Install QEMU, GDB, OVMF packages
├─► Create or obtain test disk image
├─► Verify basic QEMU operation
└─► Set up directory structure
Phase 2: SEABIOS ANALYSIS
│
├─► Run with minimal logging (-d cpu_reset)
├─► Run with interrupt logging (-d int)
├─► Attach GDB, set breakpoints
│ ├─► 0xFFFF0 (reset vector)
│ ├─► 0xF000:E05B (SeaBIOS entry)
│ └─► 0x7C00 (bootloader)
├─► Trace execution, note timestamps
├─► Document all INT calls
└─► Record memory layout changes
Phase 3: OVMF ANALYSIS
│
├─► Run with minimal logging
├─► Identify SEC, PEI, DXE, BDS phases
├─► Attach GDB, trace phase transitions
├─► Document protocol initialization
└─► Record boot timing
Phase 4: COMPARISON
│
├─► Extract metrics from both logs
│ ├─► Boot time to bootloader
│ ├─► Number of INT calls (SeaBIOS)
│ ├─► Memory usage patterns
│ └─► Device initialization order
├─► Create comparison tables
└─► Document architectural differences
Phase 5: DOCUMENTATION
│
├─► Write SeaBIOS analysis document
├─► Write OVMF analysis document
├─► Create timeline diagrams
├─► Write comparison summary
├─► Package reproducibility scripts
└─► Peer review for clarity
5. Implementation Guide
5.1 Development Environment Setup
Ubuntu/Debian (Recommended):
# Install required packages
sudo apt update
sudo apt install -y \
qemu-system-x86 \
qemu-utils \
gdb \
ovmf \
python3 \
python3-pip \
make \
nasm \
binutils
# Verify installations
qemu-system-x86_64 --version
gdb --version
ls /usr/share/OVMF/OVMF_CODE.fd
# Create project directory structure
mkdir -p vm-boot-inspector/{scripts,logs,docs,images,firmware,diagrams}
cd vm-boot-inspector
# Copy OVMF firmware (need both CODE and VARS)
cp /usr/share/OVMF/OVMF_CODE.fd firmware/
cp /usr/share/OVMF/OVMF_VARS.fd firmware/
# Make a working copy for VARS (gets modified during boot)
cp firmware/OVMF_VARS.fd firmware/OVMF_VARS_work.fd
Create Test Disk Image:
# Create a simple bootloader for testing
cat > images/boot.asm << 'EOF'
[BITS 16]
[ORG 0x7C00]
start:
cli ; Disable interrupts
xor ax, ax ; Zero AX
mov ds, ax ; Set data segment
mov es, ax ; Set extra segment
mov ss, ax ; Set stack segment
mov sp, 0x7C00 ; Set stack pointer
; Clear screen
mov ax, 0x0003 ; Set video mode 3 (80x25 text)
int 0x10
; Print message
mov si, msg
call print_string
; Halt
cli
hlt
jmp $
print_string:
lodsb ; Load byte from SI to AL
or al, al ; Check if zero
jz .done
mov ah, 0x0E ; BIOS teletype
mov bx, 0x0007 ; Page 0, light gray
int 0x10
jmp print_string
.done:
ret
msg: db 'VM Boot Inspector - Bootloader loaded!', 13, 10
db 'Press any key to continue...', 13, 10, 0
; Padding and boot signature
times 510-($-$$) db 0
dw 0xAA55
EOF
# Assemble the bootloader
nasm -f bin images/boot.asm -o images/boot.bin
# Create disk image with the bootloader
dd if=/dev/zero of=images/test_disk.img bs=1M count=10
dd if=images/boot.bin of=images/test_disk.img conv=notrunc
# Test basic boot
qemu-system-x86_64 -hda images/test_disk.img -nographic
# Press Ctrl+A, then X to exit QEMU
5.2 Project Structure
vm-boot-inspector/
├── scripts/
│ ├── trace_seabios.sh # Trace SeaBIOS boot
│ ├── trace_ovmf.sh # Trace OVMF boot
│ ├── gdb_boot.sh # GDB debugging helper
│ ├── boot_debug.gdb # GDB command script
│ ├── analyze_logs.py # Log parsing and analysis
│ ├── compare_firmware.py # Comparison generator
│ └── generate_report.sh # Create final documentation
├── logs/
│ ├── seabios_minimal.log # CPU reset info only
│ ├── seabios_int.log # Interrupt trace
│ ├── seabios_full.log # Full instruction trace
│ ├── ovmf_minimal.log
│ ├── ovmf_int.log
│ └── gdb_sessions/ # GDB transcript files
├── docs/
│ ├── SEABIOS_ANALYSIS.md # SeaBIOS boot documentation
│ ├── OVMF_ANALYSIS.md # OVMF boot documentation
│ ├── COMPARISON.md # Side-by-side comparison
│ └── METHODOLOGY.md # How analysis was performed
├── images/
│ ├── boot.asm # Test bootloader source
│ ├── boot.bin # Assembled bootloader
│ └── test_disk.img # Test disk image
├── firmware/
│ ├── OVMF_CODE.fd # OVMF firmware code
│ ├── OVMF_VARS.fd # OVMF variables template
│ └── OVMF_VARS_work.fd # Working copy (modified by boot)
├── diagrams/
│ ├── seabios_timeline.txt # ASCII timeline
│ └── ovmf_phases.txt # ASCII phase diagram
└── README.md # Project overview
5.3 The Core Question You’re Answering
How do virtual machines emulate the complete boot process, and what are the fundamental differences between virtualized and physical hardware initialization?
This project explores the abstraction layers in virtualization: What does QEMU/KVM actually emulate versus pass through? How do firmware implementations like SeaBIOS and OVMF create the illusion of real hardware? Understanding VM boot processes reveals both bootloader mechanics AND virtualization architecture—essential knowledge for cloud infrastructure, debugging, and system design.
5.4 Concepts You Must Understand First
Before building this project, verify your understanding of these prerequisite concepts:
- BIOS POST (Power-On Self-Test) sequence (Chapter 3, “BIOS Disassembly Ninjutsu Uncovered” by Darmawan Salihun)
- Self-assessment question: What hardware components does BIOS initialize during POST? What’s stored in the BIOS Data Area (BDA) at 0x400?
- Why it matters: SeaBIOS emulates this entire sequence in software
- UEFI boot phases and protocols (UEFI Specification 2.10)
- Self-assessment question: What are the differences between SEC, PEI, DXE, BDS, and RT phases? How does UEFI find boot targets?
- Why it matters: OVMF implements full UEFI stack in virtual machines
- Hardware emulation vs paravirtualization (Chapter 1, “Mastering KVM Virtualization” by Vedran Dakic)
- Self-assessment question: What’s the difference between QEMU emulating an IDE controller versus using virtio? When does KVM acceleration apply?
- Why it matters: Boot performance and device availability depend on emulation strategy
- GDB remote debugging protocol (GDB Remote Serial Protocol)
- Self-assessment question: What does
target remote localhost:1234do? How do you set architecture before the OS loads? - Why it matters: QEMU’s
-s -Sflags enable boot-time debugging
- Self-assessment question: What does
- Real mode vs protected mode addressing (Chapter 3, “PC Assembly Language” by Paul A. Carter)
- Self-assessment question: How does segmentation work in real mode? What’s the highest address accessible without A20 gate enabled?
- Why it matters: Boot code starts in real mode, transitions through protected mode to long mode
- Firmware blob loading and execution (QEMU documentation)
- Self-assessment question: What’s the difference between
-biosand-pflashin QEMU? Where are firmware variables stored in OVMF? - Why it matters: Different firmware loading methods affect boot behavior and persistence
- Self-assessment question: What’s the difference between
5.5 Questions to Guide Your Design
As you implement this project, these questions will guide critical design decisions:
Environment Setup
- Which QEMU machine type will you use (
-M pcfor legacy BIOS,-M q35for modern chipset)? - Which firmware will you test (SeaBIOS, OVMF/EDK2, both)?
- What debug logging level is appropriate (all interrupts, CPU resets, executed instructions)?
- Where will you save the extensive boot logs for analysis?
Tracing and Instrumentation
- Which QEMU debug flags reveal the most useful information (
-d int,cpu_reset,in_asm,guest_errors)? - At which memory addresses should you set breakpoints (0x7C00, 0xFFFF0, others)?
- How will you correlate log output with firmware source code?
- What timeline granularity is needed (milliseconds, instruction counts, phase markers)?
Comparison Methodology
- What metrics will you compare between SeaBIOS and OVMF (boot time, memory usage, device initialization order)?
- How will you document differences in boot device enumeration?
- What visualization format best shows the boot timeline (flowchart, sequence diagram, table)?
- How will you validate that your observations match firmware documentation?
Analysis and Documentation
- What audience will read your documentation (beginners, experienced developers, interviewers)?
- How will you structure findings (chronological, by component, by boot phase)?
- What level of detail is appropriate for each boot phase (high-level overview vs instruction-level trace)?
- How will you make your analysis reproducible for others?
5.6 Thinking Exercise
Before writing any code, perform this analysis:
Trace QEMU’s firmware loading process:
- Read QEMU source code:
hw/i386/pc.candhw/i386/pc_sysfw.c - Identify where firmware is loaded into guest memory (what address range?)
- Determine the initial CPU state (CS:IP values, register contents)
- Map out the memory layout before any firmware code runs
Compare firmware execution paths:
Run both SeaBIOS and OVMF with minimal debug output:
# SeaBIOS (default)
qemu-system-x86_64 -M pc -d int -D seabios.log -nographic -hda disk.img
# OVMF
qemu-system-x86_64 -M q35 -bios /usr/share/OVMF/OVMF_CODE.fd -d int -D ovmf.log -nographic -hda disk.img
Analyze the logs:
- How many interrupts fire before bootloader loads?
- What’s the difference in INT 13h (disk) access patterns?
- Which firmware reaches 0x7C00 faster and why?
- What additional setup does UEFI perform that BIOS doesn’t?
Expected insights:
- VM firmware is just software running at high privilege, not magic
- SeaBIOS mimics physical BIOS by executing at 0xF0000, OVMF starts differently
- Boot time differences reveal architectural complexity tradeoffs
- QEMU’s device emulation creates a consistent interface for firmware
5.7 Hints in Layers
Hint 1: Getting Started (Conceptual Direction)
Start with simple logging before using GDB. QEMU’s -d flag has many useful options—start with -d int,cpu_reset to see interrupt activity and CPU state changes. Send output to file with -D boot.log.
Don’t try to understand everything at once. First goal: trace from power-on to 0x7C00. Second goal: identify major phases (POST, device init, boot device search). Third goal: compare two firmware implementations.
Build a simple test disk image (can be just a bootloader from Project 1) so you have a known-good boot target. This isolates firmware behavior from complex OS boot code.
Hint 2: Setting Up Effective Tracing (More Specific Guidance)
Useful QEMU debug flags:
-d int # Log all interrupts (INT 10h video, INT 13h disk, etc.)
-d cpu_reset # Log CPU state at reset
-d in_asm # Log every executed instruction (VERY verbose!)
-d guest_errors # Log invalid guest operations
-d unimp # Log unimplemented features accessed
For structured analysis:
# Minimal logging (boot phases)
qemu-system-x86_64 -d int,cpu_reset -D seabios_minimal.log -hda disk.img -nographic
# Full trace (instruction level - WARNING: huge file!)
qemu-system-x86_64 -d in_asm,int -D seabios_full.log -hda disk.img -nographic | head -50000
# OVMF comparison
qemu-system-x86_64 -bios /usr/share/OVMF/OVMF_CODE.fd \
-drive if=pflash,format=raw,file=OVMF_VARS.fd \
-d int,cpu_reset -D ovmf_minimal.log -hda disk.img -nographic
Parse logs with:
grep "check_exception" boot.log | wc -l # Count interrupts
grep "0x00007c00" boot.log # Find bootloader load
grep "INT 13" boot.log # Track disk I/O
Hint 3: GDB Debugging at Boot Time (Technical Details)
Start QEMU in debug mode and connect GDB:
# Terminal 1: Start QEMU, paused at boot
qemu-system-x86_64 -s -S -hda disk.img -nographic
# Terminal 2: Connect GDB
gdb
(gdb) target remote localhost:1234
(gdb) set arch i8086 # Real mode initially
(gdb) break *0x7c00 # Break at bootloader
(gdb) break *0xFFFF0 # Break at reset vector
(gdb) continue
Useful GDB commands for boot debugging:
info registers # See all registers
x/10i $cs*16+$pc # Disassemble in real mode
x/10xb 0x7c00 # Examine bootloader memory
set architecture i386 # Switch to protected mode
set architecture i386:x86-64 # Switch to long mode
Create GDB script for automated tracing:
# boot_trace.gdb
set arch i8086
target remote localhost:1234
break *0x7c00
commands
silent
printf "Bootloader reached at 0x7C00\n"
x/10i 0x7c00
continue
end
continue
Run: gdb -x boot_trace.gdb
Hint 4: Analysis and Documentation (Tools and Verification)
Create a boot timeline by parsing logs:
# parse_boot_log.py
import re
import sys
events = []
with open(sys.argv[1]) as f:
for line in f:
# Extract interrupt calls
if match := re.search(r'INT (0x[0-9a-f]+)', line):
events.append(('INT', match.group(1)))
# Extract address jumps
if match := re.search(r'Trace.*0x([0-9a-f]+)', line):
events.append(('EXEC', match.group(1)))
# Identify phases
print("Boot timeline:")
for i, (event_type, value) in enumerate(events[:100]): # First 100 events
print(f"{i:4d}: {event_type:6s} {value}")
Compare SeaBIOS vs OVMF:
# Count interrupt usage
echo "SeaBIOS interrupts:"
grep "INT 0x" seabios.log | cut -d' ' -f2 | sort | uniq -c
echo "OVMF interrupts:"
grep "INT 0x" ovmf.log | cut -d' ' -f2 | sort | uniq -c
# Measure boot time (requires timestamps in log)
echo "Time to 0x7C00:"
grep "0x00007c00" seabios.log | head -1
grep "0x00007c00" ovmf.log | head -1
Document with diagrams:
SeaBIOS Boot Flow:
Reset (0xFFFF0) --> POST --> Option ROM scan --> INT 19h (boot)
| | |
20ms 50ms 100ms
|
Read MBR (INT 13h)
|
Jump 0x7C00 (120ms)
OVMF Boot Flow:
Reset --> SEC phase --> PEI phase --> DXE phase --> BDS phase --> Load bootloader
| | | | | |
20ms 100ms 500ms 800ms 1200ms 1500ms
Verify your findings against source code:
- SeaBIOS: https://github.com/coreboot/seabios
- OVMF: https://github.com/tianocore/edk2
- Look for boot sequence in
src/boot.c(SeaBIOS) orBdsDxe(OVMF)
5.8 The Interview Questions They’ll Ask
If you put “QEMU/KVM boot process analysis” on your resume, expect these questions:
- “Explain the difference between QEMU, KVM, and SeaBIOS/OVMF. How do they work together?”
- What they’re testing: Understanding of virtualization stack layers
- Strong answer: “QEMU is a userspace emulator that emulates devices and CPU instructions. KVM is a kernel module that accelerates CPU execution using hardware virtualization (VT-x/AMD-V). SeaBIOS/OVMF are firmware blobs loaded by QEMU that provide BIOS/UEFI environment to the guest. QEMU+KVM executes guest code, firmware initializes virtual hardware, bootloader runs in the guest.”
- “Walk through the complete boot sequence when you run
qemu-system-x86_64 -hda disk.img.”- What they’re testing: End-to-end understanding of VM initialization
- Strong answer: “QEMU process starts, loads SeaBIOS to 0xF0000, creates virtual hardware (RAM, PCI devices, disk controllers). CPU starts at reset vector 0xFFFF0 (JMP to SeaBIOS). SeaBIOS does POST, initializes PCI, finds boot devices via INT 13h. Reads MBR from disk to 0x7C00, validates 0xAA55 signature, jumps to 0x7C00. Bootloader runs.”
- “How would you debug a VM that hangs during boot with no output?”
- What they’re testing: Debugging methodology in virtualized environments
- Strong answer: “Add QEMU debug flags:
-d int,cpu_reset,in_asmto log execution. Attach GDB with-s -S, break at 0x7C00 to verify bootloader loads. Check if firmware reaches bootloader or hangs earlier. Useinfo registersandx/10i $pcin GDB. Compare logs with working boot. Check disk image integrity.”
- “What are the key differences between booting with SeaBIOS versus OVMF in QEMU?”
- What they’re testing: BIOS vs UEFI architectural knowledge
- Strong answer: “SeaBIOS provides legacy BIOS INT-based services, boots in real mode, looks for 0xAA55 MBR signature, loads one sector to 0x7C00. OVMF provides UEFI with 32/64-bit protected mode APIs, uses GPT partitions, loads PE/COFF executables from FAT ESP, supports Secure Boot. OVMF boot is slower but more flexible and secure.”
- “Explain QEMU’s device emulation strategies: full emulation, paravirtualization, and passthrough.”
- What they’re testing: Understanding of performance/compatibility tradeoffs
- Strong answer: “Full emulation (e1000 NIC): QEMU simulates hardware perfectly, slow but compatible. Paravirtualization (virtio): Guest uses special drivers knowing it’s virtualized, much faster, requires guest support. Passthrough (VFIO): Direct hardware access via IOMMU, native performance, requires compatible hardware and kernel support.”
- “How does QEMU’s
-s -Sdebugging mode work, and why set architecture before continuing?”- What they’re testing: Low-level debugging understanding
- Strong answer: “
-sopens GDB server on port 1234,-Sfreezes CPU at reset. Mustset arch i8086because boot starts in 16-bit real mode, not 32/64-bit. As boot progresses through protected mode and long mode, architecture must be changed. Otherwise GDB disassembles incorrectly and breakpoints fail.”
5.9 Books That Will Help
| Topic | Book & Chapter |
|---|---|
| QEMU architecture and internals | “Mastering KVM Virtualization” by Vedran Dakic, Chapter 1 (Understanding Linux Virtualization) and Chapter 3 (Advanced QEMU and Libvirt) |
| SeaBIOS implementation details | “BIOS Disassembly Ninjutsu Uncovered” by Darmawan Salihun, Chapter 3 (System Initialization), plus SeaBIOS source code documentation |
| UEFI/OVMF architecture and boot phases | “Beyond BIOS: Developing with the Unified Extensible Firmware Interface” by Vincent Zimmer et al., Chapter 4 (Boot Phases) and Chapter 7 (Device Drivers) |
| GDB remote debugging protocol | “The Art of Debugging with GDB, DDD, and Eclipse” by Norman Matloff, Chapter 7 (Advanced GDB), plus GDB manual |
| x86 real mode and protected mode | “PC Assembly Language” by Paul A. Carter, Chapter 3 (Protected Mode), and “Programming from the Ground Up” by Jonathan Bartlett, Chapter 10 (Low-Level Topics) |
| KVM and hardware virtualization | “Linux Kernel Development” by Robert Love, Chapter 17 (KVM Virtualization), and Intel/AMD virtualization manuals |
| Firmware standards and specifications | UEFI Specification 2.10 (uefi.org), ACPI Specification, and SMBIOS Reference |
| Boot process deep dive | “What Every Programmer Should Know About Memory” by Ulrich Drepper (understanding initialization constraints), “Professional Linux Kernel Architecture” by Wolfgang Mauerer, Chapter 15 (Boot Process) |
5.10 Implementation Phases
Phase 1: Environment Setup (Day 1)
# Create project structure
mkdir -p vm-boot-inspector/{scripts,logs,docs,images,firmware,diagrams}
cd vm-boot-inspector
# Install dependencies
sudo apt install qemu-system-x86 ovmf gdb nasm python3
# Copy OVMF firmware
cp /usr/share/OVMF/OVMF_CODE.fd firmware/
cp /usr/share/OVMF/OVMF_VARS.fd firmware/
# Create test bootloader
cat > images/boot.asm << 'EOF'
[BITS 16]
[ORG 0x7C00]
cli
xor ax, ax
mov ds, ax
mov ss, ax
mov sp, 0x7C00
mov si, msg
.loop:
lodsb
or al, al
jz .halt
mov ah, 0x0E
int 0x10
jmp .loop
.halt:
hlt
jmp .halt
msg: db 'Bootloader loaded!', 13, 10, 0
times 510-($-$$) db 0
dw 0xAA55
EOF
nasm -f bin images/boot.asm -o images/boot.bin
dd if=/dev/zero of=images/test_disk.img bs=1M count=10
dd if=images/boot.bin of=images/test_disk.img conv=notrunc
# Verify setup
qemu-system-x86_64 -hda images/test_disk.img -nographic
# Should see "Bootloader loaded!" then hang (Ctrl+A, X to exit)
Phase 2: SeaBIOS Analysis (Days 2-4)
# Create tracing script
cat > scripts/trace_seabios.sh << 'EOF'
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_DIR="logs"
DISK="images/test_disk.img"
echo "[*] Starting SeaBIOS boot trace..."
echo "[*] Log file: ${LOG_DIR}/seabios_${TIMESTAMP}.log"
timeout 10 qemu-system-x86_64 \
-M pc \
-d int,cpu_reset \
-D "${LOG_DIR}/seabios_${TIMESTAMP}.log" \
-hda "${DISK}" \
-nographic \
2>&1
echo "[*] Trace complete. Analyzing..."
echo ""
echo "=== Quick Analysis ==="
echo "INT calls:"
grep -c "check_exception" "${LOG_DIR}/seabios_${TIMESTAMP}.log" || echo "0"
echo ""
echo "First lines:"
head -50 "${LOG_DIR}/seabios_${TIMESTAMP}.log"
EOF
chmod +x scripts/trace_seabios.sh
# Run trace
./scripts/trace_seabios.sh
Phase 3: OVMF Analysis (Days 5-7)
# Create OVMF tracing script
cat > scripts/trace_ovmf.sh << 'EOF'
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_DIR="logs"
DISK="images/test_disk.img"
OVMF_CODE="firmware/OVMF_CODE.fd"
OVMF_VARS="firmware/OVMF_VARS.fd"
# Create working copy of VARS
cp "${OVMF_VARS}" "firmware/OVMF_VARS_work.fd"
echo "[*] Starting OVMF boot trace..."
echo "[*] Log file: ${LOG_DIR}/ovmf_${TIMESTAMP}.log"
timeout 30 qemu-system-x86_64 \
-M q35 \
-drive if=pflash,format=raw,readonly=on,file="${OVMF_CODE}" \
-drive if=pflash,format=raw,file="firmware/OVMF_VARS_work.fd" \
-d int,cpu_reset \
-D "${LOG_DIR}/ovmf_${TIMESTAMP}.log" \
-hda "${DISK}" \
-nographic \
2>&1
echo "[*] Trace complete."
echo ""
echo "=== Quick Analysis ==="
echo "Log size: $(wc -l < "${LOG_DIR}/ovmf_${TIMESTAMP}.log") lines"
EOF
chmod +x scripts/trace_ovmf.sh
# Run trace
./scripts/trace_ovmf.sh
Phase 4: GDB Debugging (Days 8-10)
# Create GDB script
cat > scripts/boot_debug.gdb << 'EOF'
# VM Boot Inspector - GDB Debug Script
# Connect to QEMU
target remote localhost:1234
# Set 16-bit real mode (boot starts here)
set arch i8086
# Define convenience functions
define show_regs_16
printf "AX=%04X BX=%04X CX=%04X DX=%04X\n", $eax & 0xFFFF, $ebx & 0xFFFF, $ecx & 0xFFFF, $edx & 0xFFFF
printf "SI=%04X DI=%04X SP=%04X BP=%04X\n", $esi & 0xFFFF, $edi & 0xFFFF, $esp & 0xFFFF, $ebp & 0xFFFF
printf "CS=%04X DS=%04X ES=%04X SS=%04X\n", $cs, $ds, $es, $ss
printf "IP=%04X Flags=%04X\n", $eip & 0xFFFF, $eflags & 0xFFFF
end
define show_code
x/10i ($cs * 16) + $eip
end
# Set breakpoints at key locations
echo Setting breakpoint at reset vector (0xFFFF0)...\n
break *0xFFFF0
echo Setting breakpoint at bootloader load address (0x7C00)...\n
break *0x7c00
# Commands to run at each breakpoint
commands 1
silent
printf "\n=== RESET VECTOR HIT ===\n"
show_regs_16
printf "\nFirst instructions:\n"
show_code
continue
end
commands 2
silent
printf "\n=== BOOTLOADER LOADED AT 0x7C00 ===\n"
show_regs_16
printf "\nBootloader code:\n"
x/20i 0x7c00
printf "\nMBR signature check:\n"
x/2xb 0x7dfe
end
echo \nGDB ready. Type 'continue' to start boot.\n
EOF
# Create helper script
cat > scripts/gdb_boot.sh << 'EOF'
#!/bin/bash
DISK="images/test_disk.img"
echo "[*] Starting QEMU in debug mode..."
qemu-system-x86_64 \
-M pc \
-s -S \
-hda "${DISK}" \
-nographic &
QEMU_PID=$!
sleep 1
echo "[*] Launching GDB..."
gdb -x scripts/boot_debug.gdb
# Cleanup
kill $QEMU_PID 2>/dev/null
EOF
chmod +x scripts/gdb_boot.sh
# Run GDB debugging session
./scripts/gdb_boot.sh
Phase 5: Analysis and Documentation (Days 11-14)
# scripts/analyze_logs.py
#!/usr/bin/env python3
"""
Analyze QEMU boot logs and generate comparison data.
"""
import sys
import re
from collections import Counter
from pathlib import Path
def parse_seabios_log(filepath):
"""Parse SeaBIOS interrupt log."""
events = []
int_counts = Counter()
with open(filepath) as f:
for line in f:
# Track interrupts
if 'check_exception' in line:
match = re.search(r'intno=0x([0-9a-f]+)', line)
if match:
int_num = int(match.group(1), 16)
int_counts[f'INT {int_num:02X}h'] += 1
events.append(('INT', int_num))
return {
'events': events,
'int_counts': dict(int_counts),
'total_ints': sum(int_counts.values())
}
def parse_ovmf_log(filepath):
"""Parse OVMF log."""
events = []
with open(filepath) as f:
for line in f:
if 'cpu_reset' in line.lower():
events.append(('RESET', 0))
# OVMF doesn't use INT calls like SeaBIOS
return {
'events': events,
'total_lines': sum(1 for _ in open(filepath))
}
def generate_comparison(seabios_data, ovmf_data):
"""Generate comparison report."""
print("=" * 60)
print("FIRMWARE BOOT COMPARISON")
print("=" * 60)
print()
print("SeaBIOS Analysis:")
print(f" Total interrupts: {seabios_data['total_ints']}")
print(" Top interrupt types:")
for int_type, count in sorted(seabios_data['int_counts'].items(),
key=lambda x: -x[1])[:5]:
print(f" {int_type}: {count}")
print()
print("OVMF Analysis:")
print(f" Total log lines: {ovmf_data['total_lines']}")
print(" (OVMF uses UEFI protocols, not INT calls)")
print()
print("Key Differences:")
print(" - SeaBIOS: Real mode, INT-based services")
print(" - OVMF: Protected mode, function pointer tables")
print(" - SeaBIOS boot is faster (~50-100ms)")
print(" - OVMF boot is slower but supports Secure Boot")
if __name__ == '__main__':
if len(sys.argv) < 3:
print(f"Usage: {sys.argv[0]} <seabios.log> <ovmf.log>")
sys.exit(1)
seabios_data = parse_seabios_log(sys.argv[1])
ovmf_data = parse_ovmf_log(sys.argv[2])
generate_comparison(seabios_data, ovmf_data)
6. Testing Strategy
6.1 Environment Verification
# Test 1: QEMU installation
qemu-system-x86_64 --version
# Expected: QEMU version 4.0 or later
# Test 2: OVMF firmware present
ls -la /usr/share/OVMF/OVMF_CODE.fd
# Expected: File exists, ~2MB
# Test 3: GDB can connect to QEMU
qemu-system-x86_64 -s -S -hda images/test_disk.img -nographic &
sleep 1
echo "quit" | gdb -ex "target remote localhost:1234" -ex "quit"
# Expected: GDB connects successfully
kill %1
6.2 Tracing Verification
# Test 4: SeaBIOS logging works
./scripts/trace_seabios.sh
# Expected: Log file created, contains "check_exception" entries
# Test 5: OVMF logging works
./scripts/trace_ovmf.sh
# Expected: Log file created, larger than SeaBIOS log
# Test 6: GDB breakpoints work
./scripts/gdb_boot.sh
# In GDB: continue
# Expected: Breaks at 0x7C00, shows bootloader code
6.3 Analysis Verification
# Test 7: Log parser works
python3 scripts/analyze_logs.py logs/seabios_*.log logs/ovmf_*.log
# Expected: Comparison output with interrupt counts
# Test 8: Documentation complete
ls docs/
# Expected: SEABIOS_ANALYSIS.md, OVMF_ANALYSIS.md, COMPARISON.md present
7. Common Pitfalls & Debugging
Problem 1: QEMU debug logs are overwhelming and unreadable
Root cause: Using -d in_asm generates millions of lines. No filtering applied. Trying to understand everything at once.
Fix: Start with minimal logging: -d cpu_reset only to see initial state. Add -d int to track firmware service calls. Only use -d in_asm with head -10000 or when investigating specific issue. Parse logs with grep/awk to extract relevant events. Focus on one boot phase at a time.
Quick test: Run with -d int -D boot.log, then grep "INT 13" boot.log | wc -l to count disk operations. If count seems reasonable (< 100 for simple boot), you’re at the right logging level.
Problem 2: GDB shows wrong disassembly or breakpoints don’t work
Root cause: Architecture mismatch—CPU is in real mode (16-bit) but GDB thinks it’s 32-bit or 64-bit.
Fix: Always set arch i8086 before connecting to QEMU. When firmware switches to protected mode, use set arch i386. For long mode, use set arch i386:x86-64. Watch for mode transitions in logs or use info registers to check CS register value.
Quick test: After setting breakpoint at 0x7C00, verify with x/10i 0x7c00. If you see valid bootloader instructions (likely cli, xor ax,ax, mov), architecture is correct. If gibberish, wrong arch.
Problem 3: OVMF boot is extremely slow or hangs in QEMU
Root cause: OVMF performs extensive initialization and driver loading. Without KVM acceleration, emulation is very slow.
Fix: Use KVM if available: qemu-system-x86_64 -enable-kvm. This requires Linux host with KVM module loaded (lsmod | grep kvm). OVMF boot in emulation can take minutes; with KVM it’s under 2 seconds. Disable unnecessary OVMF features in build if doing pure emulation.
Quick test: Compare boot times: time qemu-system-x86_64 -bios OVMF.fd -hda disk.img -nographic vs with -enable-kvm. Should see 10-100x speedup with KVM.
Problem 4: Cannot find where 0x7C00 is written in QEMU logs
Root cause: Disk read via DMA or device emulation doesn’t always show in CPU trace. Logs show INT 13h call but not memory write.
Fix: Use GDB memory watchpoint: watch *(char*)0x7c00. This will break when firmware writes bootloader to memory. Alternatively, use QEMU tracing: -trace events=/tmp/events with disk I/O events enabled. Check SeaBIOS source src/boot.c to understand boot device selection logic.
Quick test: Set breakpoint just before and after suspected load: break *0x7bff and break *0x7c00, examine memory at both points with x/10xb 0x7c00 to confirm it changed.
Problem 5: Documentation becomes a disorganized collection of facts
Root cause: No structure decided before investigation. Trying to document while learning. No clear audience or purpose.
Fix: Create documentation outline first: (1) Executive Summary, (2) Environment Setup, (3) Boot Timeline, (4) SeaBIOS Analysis, (5) OVMF Analysis, (6) Comparison, (7) Lessons Learned. Fill in sections as you investigate. Use consistent diagram style. Include reproduction steps so others can verify your findings.
Quick test: Have someone unfamiliar with your work read the documentation. Can they understand the boot sequence? Can they reproduce your setup? If not, add missing context and instructions.
8. Extensions & Challenges
After completing the basic project, try these extensions:
8.1 Intermediate Extensions
-
Add timing analysis: Modify scripts to capture precise timestamps at each boot phase, create visualizations showing where time is spent
-
Trace device initialization: Use
-d ioportto track all I/O port accesses, document which devices are initialized in what order -
Compare machine types: Analyze differences between
-M pc(i440FX),-M q35(ICH9), and other QEMU machine types -
Analyze memory detection: Trace how firmware discovers available RAM, document the INT 15h/E820 memory map
8.2 Advanced Extensions
-
KVM vs TCG comparison: Quantify performance differences between hardware virtualization and software emulation
-
UEFI Secure Boot analysis: Trace the Secure Boot verification process, document certificate chain validation
-
Custom firmware modification: Build SeaBIOS from source with debug output, trace specific functions
-
ACPI table generation: Document how firmware generates ACPI tables for the guest OS
8.3 Professional Extensions
-
Create interactive visualization: Build a web-based timeline viewer for boot logs
-
Automate regression testing: Create CI pipeline that detects boot performance regressions
-
Write cloud provider analysis: Compare AWS, GCP, Azure instance boot processes
-
Contribute to SeaBIOS/OVMF: Submit documentation improvements based on your analysis
9. Real-World Connections
9.1 Industry Applications
| Domain | How This Knowledge Applies |
|---|---|
| Cloud Infrastructure | Debugging VM provisioning failures, optimizing boot times, understanding hypervisor behavior |
| Security Research | Analyzing boot-time attacks, rootkit detection, Secure Boot bypass research |
| Firmware Development | Testing BIOS/UEFI implementations, regression testing, compatibility verification |
| DevOps | Troubleshooting cloud-init failures, understanding instance initialization, AMI debugging |
| Embedded Systems | Using QEMU for development before hardware available, testing boot sequences |
9.2 Career Relevance
- Site Reliability Engineer: Understanding why VMs fail to boot is critical for production incident response
- Cloud Engineer: Knowledge of VM boot process helps optimize infrastructure and debug issues
- Security Engineer: Boot process analysis is fundamental to firmware security research
- Systems Programmer: QEMU debugging skills transfer to kernel and driver development
9.3 Related Open Source Projects
- SeaBIOS: https://github.com/coreboot/seabios - The BIOS implementation you’re analyzing
- EDK2 (OVMF): https://github.com/tianocore/edk2 - The UEFI implementation
- QEMU: https://gitlab.com/qemu-project/qemu - The emulator itself
- coreboot: https://github.com/coreboot/coreboot - Open source firmware for physical hardware
10. Resources
10.1 Official Documentation
10.2 Tutorials and Guides
10.3 Community
10.4 Video Resources
- “QEMU Internals” - KVM Forum presentations
- “Understanding x86_64 Boot Process” - YouTube technical talks
11. Self-Assessment Checklist
Before considering this project complete, verify you can:
Knowledge Check
- Explain the difference between QEMU (emulator), KVM (accelerator), and SeaBIOS/OVMF (firmware)
- Describe the complete boot sequence from QEMU process start to bootloader execution
- List at least 5 QEMU debug flags and explain what each reveals
- Explain why GDB architecture must be set to i8086 for boot debugging
- Describe the architectural differences between BIOS INT services and UEFI protocols
Skills Check
- Configure QEMU with appropriate debug flags for boot tracing
- Attach GDB to QEMU and set breakpoints at boot addresses
- Parse and analyze QEMU debug logs
- Compare SeaBIOS and OVMF boot sequences quantitatively
- Create technical documentation with ASCII diagrams
Practical Check
- Successfully capture boot logs for both SeaBIOS and OVMF
- Demonstrate GDB breakpoint at 0x7C00 with register inspection
- Produce comparison table showing SeaBIOS vs OVMF metrics
- Documentation is clear enough for another engineer to reproduce analysis
12. Submission / Completion Criteria
Your implementation is complete when you can demonstrate:
- Environment: Working QEMU setup with test disk image, OVMF firmware configured
- SeaBIOS Analysis: Log capture, interrupt counting, timeline documentation
- OVMF Analysis: Log capture, phase identification, timing data
- GDB Debugging: Script that attaches GDB and breaks at 0x7C00
- Comparison: Side-by-side metrics table with analysis
- Documentation: Clear, reproducible analysis methodology
Deliverables:
scripts/directory with all tracing and analysis scriptslogs/directory with captured boot tracesdocs/SEABIOS_ANALYSIS.md- SeaBIOS boot documentationdocs/OVMF_ANALYSIS.md- OVMF boot documentationdocs/COMPARISON.md- Side-by-side comparisonREADME.md- Project overview and reproduction steps
13. Learning Milestones
Track your progress through these milestones:
| Milestone | Description | Verification |
|---|---|---|
| 1. GDB attached and breakpoints work at 0x7C00 | Debugging setup complete | Can inspect registers at bootloader load |
| 2. Full boot log analyzed | You understand every phase | Can explain each INT call in SeaBIOS log |
| 3. SeaBIOS vs OVMF differences documented | BIOS/UEFI deeply understood | Comparison table complete with metrics |
| 4. Document becomes a reference | Technical communication achieved | Another engineer can use your docs |
Previous Project: P10 - U-Boot Exploration and Customization
Next Project: P12 - Chain Loading Bootloader (Multi-Boot)