Skip to content

About

A lightweight KVM-based hypervisor written in C, featuring multiple virtual machines, configurable memory and paging, file operations, interrupts, and shared-buffer communication.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KVM Hypervisor

This project, developed for the Computer Architecture and Organization 2 course, implements a hypervisor in C using the Linux KVM API. It can run one or more 64-bit virtual machines and provides guest communication through I/O ports, local and shared file operations, interrupt handling, and data exchange through a shared buffer.

Features

A - Basic Hypervisor

  • 2 MB, 4 MB, or 8 MB of physical memory per guest;
  • paging with either 4 KB or 2 MB pages;
  • 64-bit long mode and one virtual CPU per virtual machine;
  • support for multiple guests, each running in a separate POSIX thread;
  • single-byte serial input and output through I/O port 0xE9;
  • graceful guest termination using the hlt instruction;
  • reporting of unexpected KVM exits and virtual machine errors;
  • validation of required command-line options and their values.

B - File Operations

  • guest API consisting of open, close, read, write, and lseek;
  • communication with the hypervisor through I/O port 0x278;
  • up to 32 simultaneously open files per guest;
  • isolated local files for each virtual machine;
  • shared files supplied through the -f or --file option;
  • copy-on-write semantics: the first write to a shared file creates a private guest copy, leaving the original file unchanged.

A local file named name.txt, created by guest N, is stored in the working directory as guest_N_name.txt. The same naming convention is used for private copies of shared files.

V - Interrupts and Shared Buffer

  • communication between multiple virtual machines through a 4096-byte shared buffer;
  • interrupt vector 32 for assigning roles and signaling new transfer rounds;
  • the first guest acts as the writer, while all remaining guests act as readers;
  • data transfer through port 0x510 and operation acknowledgements through port 0x520;
  • the writer starts a new round only after all active readers acknowledge the previous one;
  • data exceeding BUFFER_SIZE is accepted only up to the buffer capacity.

Project Structure

host/
├── inc/                 # Hypervisor headers
└── src/
    ├── main.c           # Guest threads and the KVM run loop
    ├── vm.c             # VM creation, memory, and paging
    ├── cli.c            # Command-line parsing and validation
    ├── file_service.c   # File protocol and copy-on-write
    └── buffer_service.c # Shared buffer and synchronization

guest/
├── inc/                 # Guest API, IDT/GDT, and I/O helpers
├── src/
│   ├── main.c           # Guest entry point
│   ├── file.c           # File operation wrappers
│   ├── buffer.c         # Shared-buffer read and write operations
│   └── interrupts.c     # Interrupt handlers
├── tests/               # Tests for all three project stages
├── guest.ld             # Linker script
└── Makefile

common/protocol.h        # Shared ports, operations, and constants

The following interfaces are used for communication between the guests and the host:

Purpose Port Direction
Serial input/output 0xE9 Guest ↔ host
File operations 0x278 Guest ↔ host
Shared-buffer role and data 0x510 Guest ↔ hypervisor
Operation result and reader acknowledgement 0x520 Guest ↔ hypervisor

Requirements

The project is intended to run on an x86-64 Linux system with hardware virtualization enabled.

Required software and system features:

  • a Linux kernel with KVM support and an accessible /dev/kvm device;
  • GCC and GNU binutils (gcc and ld);
  • GNU Make;
  • the POSIX threads library.

On Debian or Ubuntu, the required development tools can be installed with:

sudo apt install build-essential

Verify that the current user can access KVM:

test -r /dev/kvm -a -w /dev/kvm && echo "KVM is available"

If the current user cannot access /dev/kvm, configure membership in the appropriate system group or run the project in an environment that provides KVM access. WSL without nested virtualization support is not sufficient.

Building

Run the following commands from the repository root:

make -C host
make -C guest

The build produces:

  • host/build/hypervisor - the hypervisor executable;
  • guest/build/guest.img - the guest binary image.

To remove generated build files:

make -C host clean
make -C guest clean

Usage

General command syntax:

./host/build/hypervisor \
  --memory <2|4|8> \
  --page <4|2> \
  --guest <guest1.img> [guest2.img ...] \
  [--file <shared1> <shared2> ...]
Option Short form Description
--memory -m Memory allocated to each VM in MB: 2, 4, or 8.
--page -p Page size: 4 selects 4 KB pages and 2 selects 2 MB pages.
--guest -g One or more guest images; a separate VM is created for each image.
--file -f Optional list of files shared with the guests for reading.

Minimal example:

./host/build/hypervisor -m 2 -p 4 -g guest/build/guest.img

Example with three guests and one shared file:

./host/build/hypervisor \
  -m 4 -p 2 \
  -g guest/build/guest.img guest/build/guest.img guest/build/guest.img \
  -f shared/input.txt

All options except --file are required. The hypervisor terminates with an error if an option is missing, specified more than once, or given an unsupported value.

Guest File API

The guest/inc/file.h header exposes the following interface:

int open(const char *path, int flags);
int close(int fd);
int read(int fd, char *buf, int count);
int write(int fd, const char *buf, int count);
int lseek(int fd, const int offset, int off_flag);

Supported flags:

Flag Value Description
O_RD 1 Open for reading only.
O_WR 2 Open for writing only.
O_RDWR 4 Open for reading and writing.
O_CREATE 8 Create the file if it does not exist.
SEEK_SET 1 Move to the specified offset from the beginning.
SEEK_END 2 Move to the end of the file.

A file name must start with a letter and may contain letters, digits, and periods. Guests use file names without directory paths. For shared files, the hypervisor compares this name with the base name of each path supplied through --file.

Testing

The guest/tests directory contains tests for basic I/O, error validation, file operations, copy-on-write behavior, and shared-buffer transfers. Build the hypervisor before running the tests:

make -C host

Basic Serial I/O

make -C guest TEST=a_serial TEST_MAIN=1
./host/build/hypervisor -m 2 -p 4 -g guest/build_a_serial/guest.img

Local Files

make -C guest TEST=b_local TEST_MAIN=1
rm -f guest_0_localtest.txt
./host/build/hypervisor -m 2 -p 4 -g guest/build_b_local/guest.img

Copy-on-Write

make -C guest TEST=b_cow TEST_MAIN=1
rm -f guest_0_cow.txt guest_1_cow.txt
./host/build/hypervisor \
  -m 2 -p 4 \
  -g guest/build_b_cow/guest.img guest/build_b_cow/guest.img \
  -f shared/cow.txt

After the test, shared/cow.txt should remain unchanged, while each guest's modifications should appear in its private copy.

Multiple Shared-Buffer Rounds

make -C guest TEST=buffer_rounds
./host/build/hypervisor \
  -m 2 -p 4 \
  -g guest/build_buffer_rounds/guest.img \
     guest/build_buffer_rounds/guest.img \
     guest/build_buffer_rounds/guest.img

A successful test prints one W, one R for each reader, and terminates with exit status 0.

File Transfer Between Guests

make -C guest TEST=file_transfer
rm -f guest_1_received.txt guest_2_received.txt

./host/build/hypervisor \
  -m 2 -p 4 \
  -g guest/build_file_transfer/guest.img \
     guest/build_file_transfer/guest.img \
     guest/build_file_transfer/guest.img \
  -f shared/input.txt

cmp shared/input.txt guest_1_received.txt
cmp shared/input.txt guest_2_received.txt

The expected output contains one FILE SEND COMPLETE message for the writer and one FILE RECEIVE COMPLETE message for each reader. Both cmp commands should complete without reporting any differences.

Additional scenarios and commands are documented in guest/tests/testovi.txt and guest/tests/a_cli.txt.

Notes

  • The order of images following --guest determines each guest's index; guest 0 is assigned the writer role.
  • Run the program from the repository root so that relative paths and generated local files remain predictable.
  • A KVM_EXIT_HLT message represents the expected termination of a virtual machine.
  • Files inside the build and build_* directories are build artifacts and can be regenerated from the source code.

About

A lightweight KVM-based hypervisor written in C, featuring multiple virtual machines, configurable memory and paging, file operations, interrupts, and shared-buffer communication.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages