<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/kvm-host-in-a-few-lines-of-code-ug1qlexur" -->

---
title: KVM host in a few lines of code | daily.dev
description: A hands-on walkthrough of building a minimal KVM-based virtual machine host from scratch in C, using ioctl syscalls against /dev/kvm. It covers the three API...
canonical: https://daily.dev/posts/kvm-host-in-a-few-lines-of-code-ug1qlexur
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: KVM host in a few lines of code | daily.dev
og:description: A hands-on walkthrough of building a minimal KVM-based virtual machine host from scratch in C, using ioctl syscalls against /dev/kvm. It covers the three API...
og:url: https://daily.dev/posts/kvm-host-in-a-few-lines-of-code-ug1qlexur
og:image: https://api.daily.dev/og/posts/uG1QleXUr.png
og:image:alt: KVM host in a few lines of code
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# KVM host in a few lines of code

**[zserge's blog](https://daily.dev/sources/zserge)** · 10 min read · 0 upvotes · 0 comments

## Summary

A hands-on walkthrough of building a minimal KVM-based virtual machine host from scratch in C, using ioctl syscalls against /dev/kvm. It covers the three API layers (KVM, VM, VCPU), creating a VM, allocating memory, loading a tiny 16-bit assembly guest, running it and handling I/O exits. It then extends the approach to boot an actual Linux kernel (bzImage), covering protected mode register setup, boot parameters, TSS/IRQ chip initialization, and serial console output. Complete source is shared via gist, along with pointers to libvirt and kvmtool for further exploration.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://zserge.com/posts/kvm>

## Questions this post answers

### How do I create a basic virtual machine using the Linux KVM API directly with ioctl calls?

Open /dev/kvm with O_RDWR, then call ioctl with KVM_CREATE_VM on that file descriptor to get a VM file descriptor. Allocate guest RAM with mmap and register it via KVM_SET_USER_MEMORY_REGION on the VM fd, then create a virtual CPU with KVM_CREATE_VCPU. Load guest code into the mapped memory, initialize registers with KVM_SET_SREGS and KVM_SET_REGS, then loop calling KVM_RUN on the VCPU fd and handle exit reasons like KVM_EXIT_IO.

_daily.dev surfaces low-level systems programming guides for developers experimenting with virtualization internals._

### What extra ioctl setup is needed to boot a real Linux kernel bzImage inside a custom KVM host instead of a simple 16-bit program?

Booting an actual Linux kernel requires enabling protected mode instead of real mode: set KVM_SET_TSS_ADDR, KVM_SET_IDENTITY_MAP_ADDR, create an interrupt controller with KVM_CREATE_IRQCHIP, and add a periodic timer with KVM_CREATE_PIT2. Registers must set cr0's protection bit, base/limit/granularity on segment registers, rip to 0x100000 for kernel code, and rsi to 0x10000 for boot parameters parsed from the bzImage header at offset 0x1f1.

_developers building hypervisor tooling can track deep KVM internals guides through daily.dev._

### Why does a custom KVM guest Linux kernel fail to boot even after loading the bzImage and setting up protected mode correctly?

A custom-built kernel may fail to start because it checks a CPU ID to determine whether it is running inside a hypervisor versus on bare metal, so a fake CPU ID must be set for the guest to proceed. Additionally, appending "console=ttyS0" to the kernel command line is required so kernel logs get routed to the serial port the host intercepts.

_daily.dev helps engineers debugging kernel boot issues keep up with obscure KVM configuration gotchas._

## Similar posts on daily.dev

- [Building Your Own Operating System From Scratch \(A Practical Getting-Started Guide\)](https://daily.dev/posts/building-your-own-operating-system-from-scratch-a-practical-getting-started-guide--bcelcqpq7) · Medium · 0 upvotes · 0 comments
- [Making a micro Linux distro](https://daily.dev/posts/making-a-micro-linux-distro-opv8lmaob) · Hacker News · 21 upvotes · 3 comments
- [On Ditching Vagrant](https://daily.dev/posts/on-ditching-vagrant-j0ekatxsa) · Lobsters · 1 upvotes · 0 comments
- [Linux 7.1 KVM Adds "Very Experimental" Support For pKVM Protected Guests](https://daily.dev/posts/linux-7-1-kvm-adds-very-experimental-support-for-pkvm-protected-guests-dq4sdbdoa) · Phoronix · 0 upvotes · 0 comments

---

Tags: [#linux](https://daily.dev/tags/linux), [#infrastructure](https://daily.dev/tags/infrastructure), [#c](https://daily.dev/tags/c)

[View this post on daily.dev](https://daily.dev/posts/kvm-host-in-a-few-lines-of-code-ug1qlexur)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"KVM host in a few lines of code","url":"https://daily.dev/posts/kvm-host-in-a-few-lines-of-code-ug1qlexur","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/kvm-host-in-a-few-lines-of-code-ug1qlexur"},"datePublished":"2026-08-23T10:20:14.039Z","dateModified":"2026-08-23T10:20:43.639Z","description":"A hands-on walkthrough of building a minimal KVM-based virtual machine host from scratch in C, using ioctl syscalls against /dev/kvm. It covers the three API...","image":"https://media.daily.dev/image/upload/s--HRgLpUt6--/f_auto/v1722860399/public/Placeholder%2003","thumbnailUrl":"https://media.daily.dev/image/upload/s--HRgLpUt6--/f_auto/v1722860399/public/Placeholder%2003","isAccessibleForFree":true,"articleSection":"zserge's blog","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"zserge's blog","logo":"https://media.daily.dev/image/upload/s--KQnFBOIT--/f_auto,q_auto/v1787480407/logos/zserge","url":"https://daily.dev/sources/zserge"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/kvm-host-in-a-few-lines-of-code-ug1qlexur","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"linux,infrastructure,c","timeRequired":"PT10M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"zserge's blog","item":"https://daily.dev/sources/zserge"},{"@type":"ListItem","position":3,"name":"KVM host in a few lines of code"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/kvm-host-in-a-few-lines-of-code-ug1qlexur#faq","mainEntity":[{"@type":"Question","name":"How do I create a basic virtual machine using the Linux KVM API directly with ioctl calls?","acceptedAnswer":{"@type":"Answer","text":"Open /dev/kvm with O_RDWR, then call ioctl with KVM_CREATE_VM on that file descriptor to get a VM file descriptor. Allocate guest RAM with mmap and register it via KVM_SET_USER_MEMORY_REGION on the VM fd, then create a virtual CPU with KVM_CREATE_VCPU. Load guest code into the mapped memory, initialize registers with KVM_SET_SREGS and KVM_SET_REGS, then loop calling KVM_RUN on the VCPU fd and handle exit reasons like KVM_EXIT_IO. daily.dev surfaces low-level systems programming guides for developers experimenting with virtualization internals."}},{"@type":"Question","name":"What extra ioctl setup is needed to boot a real Linux kernel bzImage inside a custom KVM host instead of a simple 16-bit program?","acceptedAnswer":{"@type":"Answer","text":"Booting an actual Linux kernel requires enabling protected mode instead of real mode: set KVM_SET_TSS_ADDR, KVM_SET_IDENTITY_MAP_ADDR, create an interrupt controller with KVM_CREATE_IRQCHIP, and add a periodic timer with KVM_CREATE_PIT2. Registers must set cr0's protection bit, base/limit/granularity on segment registers, rip to 0x100000 for kernel code, and rsi to 0x10000 for boot parameters parsed from the bzImage header at offset 0x1f1. developers building hypervisor tooling can track deep KVM internals guides through daily.dev."}},{"@type":"Question","name":"Why does a custom KVM guest Linux kernel fail to boot even after loading the bzImage and setting up protected mode correctly?","acceptedAnswer":{"@type":"Answer","text":"A custom-built kernel may fail to start because it checks a CPU ID to determine whether it is running inside a hypervisor versus on bare metal, so a fake CPU ID must be set for the guest to proceed. Additionally, appending \"console=ttyS0\" to the kernel command line is required so kernel logs get routed to the serial port the host intercepts. daily.dev helps engineers debugging kernel boot issues keep up with obscure KVM configuration gotchas."}}]}
```

