Add a 'Build Architecture' section explaining the substrate approach (Ventoy modsrc as the GRUB binary), the runtime bridge via the hiperiso_boot GRUB script function, the two hardcoded layout constraints (FAT label 'VTOYEFI', /ventoy/ventoy.cpio at the ESP root), and the modsrc sed-patch strategy. Without this, a future contributor reading the build script will not understand why BOOTX64.EFI has ventoy_* symbols and the source tree has unused hiperiso_*.c files; they will likely try another incomplete rebrand.
hiperiso
A hypervisor-based ISO boot tool with full bootlogging. It boots ISOs inside a KVM + QEMU virtual machine and captures the entire boot (serial console, disk I/O, PCI/port I/O traces). The guest OS runs completely unmodified.
USB → GRUB2 → minimal Linux kernel (KVM built-in) + initramfs →
QEMU (KVM accel) → OVMF UEFI → ISO boots as an emulated CD-ROM
How it works
hiperiso presents the ISO as a native emulated AHCI CD-ROM to a KVM guest, so no guest modification is needed and the hypervisor has full visibility into every I/O operation.
Prerequisites
Build host
- A Linux x86_64 machine with VT-x / AMD-V
- Build tools:
gcc,g++,make,bc,flex,bison,cpio,gzip,wget,tar - EDK2 build deps:
nasm,iasl(acpica),python3 - QEMU build deps:
ninja-build,pkg-config,libglib2.0-dev,libpixman-1-dev - Kernel build deps:
libelf-dev,libssl-dev - ~6 GB free disk for sources + build trees
Install host (where you prepare the USB)
sgdisk(packagegdisk/gptfdisk)dosfstools(mkfs.vfat)exfatprogs(mkfs.exfat) orntfs-3g(mkntfs)grub2-efi-amd64+grub2-efi-amd64-modules(providesgrub-install --target=x86_64-efi)util-linux(findmnt,lsblk)
Target machine (the PC you boot from USB)
- x86_64 with hardware virtualization (VT-x/AMD-V) enabled in BIOS/UEFI
- UEFI boot mode (a Legacy/CSM path is planned, not in the MVP)
Build
1. One-shot full build
./scripts/build_all.sh
This downloads sources, builds the kernel, QEMU, OVMF, GRUB2, the log tool,
packs the initramfs, and assembles a distributable payload in build/payload/.
Re-run later without re-downloading:
SKIP_DOWNLOAD=1 ./scripts/build_all.sh
2. Build individual components
Each stage is a standalone script:
./scripts/download_sources.sh # fetch + extract kernel, qemu, edk2, grub2, busybox
cd build/linux && cp ../../host/kernel/hiperiso_defconfig .config && make olddefconfig && make -j"$(nproc)" bzImage
cd build/qemu && ../../scripts/configure_qemu.sh && make -j"$(nproc)" qemu-system-x86_64
cd build/edk2 && bash ../../firmware/build_ovmf.sh
Or use the provided Makefile:
make all # kernel qemu ovmf grub2 initramfs hiperiso-log
make dist # assemble build/payload/
make clean # remove build/
3. Output layout
build/payload/
├── Hiperiso2Disk.sh
├── config/hiperiso.json.example
└── EFI/
├── BOOT/
│ ├── BOOTX64.EFI # GRUB2 (hiperiso module)
│ └── grub.cfg
└── hiperiso/
├── vmlinuz # host kernel (KVM built-in)
├── initramfs.cpio.gz # busybox + qemu + init
├── OVMF.fd # guest UEFI firmware (SMM + Secure Boot)
├── hiperiso-log # log analysis tool
└── trace/ # trace-*.events (standard/detailed/full)
Install to a USB drive
⚠️ This destroys all data on the target device. Double-check the device name.
lsblk # identify your USB, e.g. /dev/sdX
sudo bash build/payload/Hiperiso2Disk.sh -I -g /dev/sdX
Hiperiso2Disk.sh defaults to MBR. Use -g for GPT. The standard
layout is:
| # | Type | FS | Size | Contents |
|---|---|---|---|---|
| 1 | 0700 | exFAT | rest | Your ISOs + boot logs + config |
| 2 | EF00 | FAT16 | 64 MB | ESP: GRUB2, kernel, initramfs, OVMF |
Copy your ISOs:
cp my_os.iso /media/$USER/HIPERISO/ISOs/
Options:
sudo bash Hiperiso2Disk.sh -i /dev/sdX # install
sudo bash Hiperiso2Disk.sh -I -g /dev/sdX # force reinstall using GPT
sudo bash Hiperiso2Disk.sh -i -L MYUSB /dev/sdX # custom data-partition label
Usage
- Boot the PC from the USB (pick the UEFI entry).
- GRUB2 lists ISOs found under
/ISOs/. Select one. - GRUB2 boots the host kernel; the initramfs detects
/dev/kvmand launches QEMU with the selected ISO attached as a CD-ROM. - The ISO's OS boots unmodified inside the VM.
- On guest shutdown, logs are flushed to the data partition.
View boot logs
Every boot gets its own timestamped session directory so logs are never overwritten:
<data partition>/hiperiso/logs/<iso-basename>_<UTC-timestamp>/
Mount the data partition on any machine and point the log tool at a session directory:
hiperiso-log analyze /hiperiso/logs/ubuntu-24.04_20260629T101530Z/
hiperiso-log trace /hiperiso/logs/ubuntu-24.04_20260629T101530Z/trace.bin --format json
hiperiso-log serial /hiperiso/logs/ubuntu-24.04_20260629T101530Z/serial.log --stages
Three files are guaranteed in every session directory, even when the boot fails before QEMU launches:
session.json # session manifest (structured metadata for agents)
status.json # live status, rewritten at every stage transition
env.txt # host environment snapshot (kernel, RAM, CPU, KVM, config)
The remaining files appear depending on how far the boot progressed:
serial.log # UART text (written by QEMU, Tier 1)
trace.bin # QEMU simpletrace (Tier 2+, only when trace_level != none)
qemu.cmdline # exact QEMU command line used
monitor.sock # QEMU monitor socket (live introspection while guest runs)
timing.dat # raw boot phase timing data (TSV: phase<TAB>uptime<TAB>iso8601)
timing.json # structured boot timing with per-phase deltas (agent-friendly)
hw/ # hardware inventory directory (see below)
network.pcap # network packet capture (only when net_dump is enabled)
report.json # generated analysis report (auto-run after QEMU exits)
report.txt # human-readable report
report.log # raw output from the analyze run
analysis.meta # flat KEY=VALUE derived analysis sidecar
HEARTBEAT # periodic liveness marker from the flush daemon
SESSION_COMPLETE # sentinel, present when the session finished (success or failure)
FAILURE.txt # human-readable failure summary (present only on failure)
Hardware inventory (hw/)
Every session collects a comprehensive hardware inventory from both the host (initramfs kernel) and the guest (QEMU virtual machine). This data provides ground truth about exactly what hardware the guest OS sees — invaluable for OS development, driver writing, and agentic debugging.
Host-side data (always present)
Collected from /proc and /sys before QEMU launches. Describes the real
hardware the initramfs kernel sees.
hw/
├── host_cpuinfo.txt # full /proc/cpuinfo
├── host_meminfo.txt # full /proc/meminfo
├── host_interrupts.txt # /proc/interrupts
├── host_iomem.txt # /proc/iomem (physical memory map)
├── host_ioports.txt # /proc/ioports
├── host_cmdline.txt # /proc/cmdline
├── host_version.txt # /proc/version
├── host_diskstats.txt # /proc/diskstats
├── host_pci_devices.txt # /proc/bus/pci/devices
├── host_cpu_cache.txt # CPU cache topology (levels, sizes, sharing)
├── host_cpu_topology.txt # CPU core/socket/thread IDs
├── host_numa.txt # NUMA node topology
├── host_iommu.txt # IOMMU groups (VT-d/AMD-Vi)
├── host_kvm.txt # /dev/kvm presence
├── host_block.txt # block device info
├── host_usb.txt # USB device tree (vendor/product IDs)
├── host_dmi.txt # DMI/SMBIOS identifiers (board, BIOS, product)
├── host_efi.txt # EFI firmware info (if UEFI boot)
├── host_dmesg.txt # host kernel boot messages
├── host_kernel_config.gz # kernel .config (if /proc/config.gz available)
├── acpi/ # host ACPI tables (binary: DSDT, FACP, APIC, MCFG...)
├── smbios/ # host DMI/SMBIOS raw tables
└── kvm_caps.json # KVM capabilities (module params: nested, ept, vpid...)
Guest-side data (present if QEMU ran ≥ 3 seconds)
Collected via QEMU HMP monitor pipe. Describes the virtual hardware the guest OS sees. Not all files may be present — depends on QEMU version and configuration.
hw/
├── qemu_version.txt # QEMU version string
├── qemu_qtree.txt # full QEMU device tree (buses, devices, properties)
├── qemu_pci.txt # PCI device list as seen by guest
├── qemu_cpuid.txt # CPUID leaves exposed to guest
├── qemu_memmap.txt # guest memory map (hierarchical view)
├── qemu_memmap_flat.txt # guest memory map (flat view, all regions)
├── qemu_ioapic.txt # IO-APIC interrupt routing state
├── qemu_lapic.txt # Local APIC state per vCPU
├── qemu_irq.txt # IRQ statistics (delivery counts)
├── qemu_registers.txt # CPU register snapshot (RAX-R15, RIP, flags, segments)
├── qemu_tlb.txt # TLB entries (TCG mode only)
├── qemu_numa.txt # guest NUMA topology
├── qemu_hpet.txt # HPET timer state
├── qemu_qomtree.txt # QOM object hierarchy
├── qemu_smbios.txt # SMBIOS table (if QEMU supports info smbios)
├── qemu_chardev.txt # QEMU character devices
├── qemu_block.txt # QEMU block devices (CD-ROM, disk, floppy)
├── qemu_net.txt # QEMU network devices
├── qemu_monitor_raw.txt # raw combined monitor output (all sections)
└── pci_summary.json # structured PCI device list (bus/dev/fn, vendor/device IDs)
Host files are always present. QEMU files appear only if QEMU launched successfully and the guest ran long enough for the monitor commands to execute (3-second delay after QEMU start).
Boot timing (timing.json)
Records microsecond-precision timestamps at each boot phase transition
using /proc/uptime as a monotonic clock. Lets agents and developers
identify performance bottlenecks across the full hypervisor boot stack.
{
"total_duration_s": 15.234,
"phases": [
{"phase": "kernel_start", "uptime_s": 0.512, "timestamp_utc": "...", "delta_s": null},
{"phase": "session_created", "uptime_s": 2.341, "timestamp_utc": "...", "delta_s": 1.829},
{"phase": "env_written", "uptime_s": 2.520, "timestamp_utc": "...", "delta_s": 0.179},
{"phase": "kvm_checked", "uptime_s": 2.890, "timestamp_utc": "...", "delta_s": 0.370},
{"phase": "iso_verified", "uptime_s": 2.910, "timestamp_utc": "...", "delta_s": 0.020},
{"phase": "qemu_launching", "uptime_s": 3.001, "timestamp_utc": "...", "delta_s": 0.091},
{"phase": "qemu_started", "uptime_s": 3.102, "timestamp_utc": "...", "delta_s": 0.101},
{"phase": "qemu_exited", "uptime_s": 14.567, "timestamp_utc": "...", "delta_s": 11.465},
{"phase": "qemu_returned", "uptime_s": 14.570, "timestamp_utc": "...", "delta_s": 0.003},
{"phase": "report_done", "uptime_s": 15.200, "timestamp_utc": "...", "delta_s": 0.630},
{"phase": "session_finalized","uptime_s": 15.234, "timestamp_utc": "...", "delta_s": 0.034}
]
}
SESSION_COMPLETE is the signal that the session finished and all logs were
flushed. If it is absent, check status.json for the last known stage and
HEARTBEAT to see whether the flush daemon was still alive.
For cross-session ingestion, hiperiso also appends one compact JSON object per session to:
<data partition>/hiperiso/logs/index.jsonl
The session manifest (session.json) is written when the session starts and
rewritten at the end as the canonical final manifest. For the live in-progress
state, read status.json:
{
"session_id": "ubuntu-24.04_20260629T101530Z",
"status": "started",
"iso_path": "/ISOs/ubuntu-24.04-desktop-amd64.iso",
"iso_basename": "ubuntu-24.04-desktop-amd64.iso",
"log_dir": "/hiperiso/logs/ubuntu-24.04_20260629T101530Z",
"start_time_utc": "2026-06-29T10:15:30Z",
"kvm": "available",
"trace_level": "standard",
"guest_ram_mb": 2048,
"guest_cpus": 2
}
The final manifest (rewritten at session end) adds end_time_utc, result,
qemu_exit_code, report_available, host (CPU model, RAM, virt support),
analysis (boot result, failure domain, error count, timing), and
hw_inventory (list of collected hardware data files).
Fallback mode
If /dev/kvm is absent (virtualization disabled) and hiperiso_fallback is
not set, hiperiso captures a failure session rather than launching a guest.
The session directory still gets session.json, status.json, and env.txt,
plus a FAILURE.txt explaining what went wrong, and the analysis report is
generated. Set hiperiso_fallback=1 to force TCG software emulation instead:
the ISO boots (very slowly) with full logging enabled.
Configuration
Edit /hiperiso/hiperiso.json on the data partition (copied from
config/hiperiso.json.example). See config/README.md
for every option. Highlights:
{
"control": { "default_ram": 2048, "default_trace_level": "standard" },
"iso_overrides": {
"*./windows11*.iso": { "ram": 4096, "tpm": true, "cpu_features": ["vmx"] }
}
}
Trace tiers: standard (serial + disk I/O), detailed (+ PCI/port I/O),
full (+ every MMIO access — very slow, debug only).
Network capture: set "net_dump": true in control_ext or per-ISO in
iso_overrides to capture all guest network traffic as a pcap file
(network.pcap in the session directory). Adds a virtio-net-pci device
to the guest and a QEMU filter-dump.
Troubleshooting
/dev/kvm missing → "Falling back to direct boot mode."
Enable VT-x/AMD-V in the host BIOS/UEFI. hiperiso then uses hypervisor mode
with full logging. Disabling Secure Boot on the host may also be required.
Guest boots to OVMF shell or hangs.
- Ensure the ISO is a valid hybrid/UEFI-bootable image.
- Try
trace_level: detailedand inspectserial.logfor the failure point. - Windows 11 ISOs need
tpm: trueand aswtpmsocket — seeconfig/iso_overrides/windows11.json.
USB not booting.
- Boot in UEFI mode (not Legacy/CSM).
- Re-run the installer and confirm
EFI/BOOT/BOOTX64.EFIexists on the ESP. - Some firmums need the USB entry added manually via the boot menu (F12/F8).
grub-install failed.
Install grub2-efi-amd64 and grub2-efi-amd64-modules (Debian/Ubuntu) or
grub2-efi-x64 + grub2-efi-x64-modules (Fedora/RHEL).
Build: OVMF step fails.
Install nasm, iasl (acpica-tools), python3, and run from inside
build/edk2. The script builds EDK2 BaseTools first; ensure make and a
recent GCC (GCC5 toolchain = GCC 5+) are present.
QEMU configure complains about missing deps.
Install ninja-build, libglib2.0-dev, libpixman-1-dev, pkg-config.
Project layout
hiperiso/
├── scripts/ # build_all, download_sources, configure_qemu, build_initramfs
├── host/kernel/ # hiperiso_defconfig (minimal KVM kernel)
├── host/initramfs/ # init scripts (separate task)
├── firmware/ # build_ovmf.sh
├── grub2/ # GRUB2 hiperiso module (separate task)
├── logging/ # trace-*.events + hiperiso-log tool (separate task)
├── installer/ # Hiperiso2Disk.sh
├── config/ # hiperiso.json.example + per-ISO overrides
├── Makefile
└── INTERFACES.sh # single source of truth for all interfaces