Writing Hypervisor in Zig

note
This blog series has been translated to the following languages:
You can switch the language by clicking the earth icon on the top right corner of the page.
Note that Japanese version is original and all other versions can be outdated. When you see Japanese sentences in translated versions, it means the translation is not yet available. Please request a translation at the GitHub repository, or contribute to the translation if you can.
Writing Hypervisor in Zig is a blog series where we implement a Type-1 hypervisor from scratch using the Zig language. In order to implement a bare-metal Hypervisor that runs at a lower level than an operating system, we will build the bootloader, kernel, and VMM components from scratch.
This series implements a Hypervisor named Ymir. Ymir runs on Intel 64 (x86-64) CPUs and takes advantage of hardware virtualization support provided by Intel VT-x. Ymir has the following features:
- Type-1 Hypervisor: No dependency on OS
- Can boot Linux: Ymir implements enough functionality to boot the Linux kernel
- Written from Scratch: No dependence on libraries, etc.
- Thin Hypervisor: Ymir intervenes with a guest only when necessary, otherwise pass-through everything
For the simplicity, Ymir has the following constraints:
- SMP (Symmetric Multi-Processing) is not supported
- Development on QEMU is expected, and Ymir has not been tested on actual devices.
- It should require some modification to run on a real machine.
- APIC is not supported
- Multiple guest VM at a time is not supported
The series consists of about 30 chapters in total, each containing both conceptual and implementation explanations of a topic. By reading the chapters and writing the actual code, you will finally impuement a hypervisor that can boot Linux:

Intended Reader
This series is intended for the following readers:.
- Some understanding of the OS or willingness to investigate on their own
- Some understanding of the x86-64 architecture or willingness to read and examine manuals
- Interest in, experience with, or willingness to study through references to the Zig language
- Willingness to write a low-level code from scratch
- CPU that supports Intel VT-x
On the other hand, this blog is not suitable for those who:
- don't want to use a non-popular language
- Never want to look up a language or CPU reference on your own
- Cannot tolerate feature reductions for simplicity or sacrifice of some rigor
- don't have Intel 64 CPU
How to Read
This series is intended to be read in order from Chapter 1. Each chapter has dependencies on the previous chapters, and code that has already appeared is treated as implemented.
It is strongly recommended that you actually wr te the code in this series by your own. The reference implementation, Ymir, is available on Github. The final code for each chapter corresponds to the whiz-*
branch in the above repository. whiz
stands for Writing Hypervisor in Zig. You can refer to the corresponding branch to see what was omitted in the chapter or what was not clear in the snippet.
Note that code in the whiz-*
branch may have some features reduced or simplified from the one in the master
branch for simplicity. Also note that the fixes will not be applied to all branches, but only to the most recent whiz-*
and master
branches.
Notations
A snippet of code is presented in a code block like:
const x: u8 = 0xDEADBEEF;
A code block with a file name means new code to be added for that file. In such cases ...
is used to omit existing code:
fn main() !void {
...
const new_code = 0xDEADBEEF;
...
}
Codes with .tmp.
in the filename mean that they are added temporarily for experimentation. Such code should be removed at the end of the chapter:
const tmp: u8 = 0xDEADBEEF;
Zig's struct
and enum
fields are denoted in the text as .field
. As an example, the following structure fields is denoted as .one
or Some.one
:
const Some = struct {
one: u8,
two: u16,
};
For registers, the N-th through M-th bits are represented as Register[M:N]
. In this case, note that the M-th bit is included.
Contributions
Please request an update from the author if you
- Found a technical error in the description
- Found an expression that is difficult to understand
- Found typo or omissions
- Found that code presented does not work or is difficult to understand
- Like to see new content that is still not covered in this series
You can request by creating Issue or Pull Request on GitHub. It is not necessary to create an Issue before creating a PR. We welcome any kind of requests and fixes.
References
The primary reference in this series is Intel® 64 and IA-32 Architectures Software Developer Manuals, hereafter abbreviated as SDM. For images taken from the SDM, the caption should read "SDM Vol.<Volume> <Chapter>. <Section>. <Subsection>". All images extracted from SDM are the property of © Intel Corporation.
Other than SDM, the following information is available for reference:
- BitVisor
- ZystemOS/pluto: An x86 kernel written in Zig
- AndreaOrru/zen : Experimental operating system written in Zig
- nuta/resea: A microkernel-based hackable operating system.
- ハイパーバイザの作り方
- ゼロからの OS 自作入門
- 5 Days to Virtualization: A Series on Hypervisor Development - Reverse Engineering
- Hypervisor From Scratch - Rayanfam Blog
- Writing OS in Rust
Other referenced information is provided on each page.
License
See License.
Privacy
This website uses Google Analytics for access analysis. You can disable cookies for this site in your browser settings.
Changelog
Date | Log |
---|---|
2024.11.17 | Published |