blob: 6c30ba7afe66e99d7a442c24198e059d08163ef2 [file] [log] [blame]
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/kvm.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "helpers.h"
int get_kvm(void)
{
int kvm, ret;
kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
if (kvm < 0)
err(kvm, "/dev/kvm");
/* Ensure this is the stable version of the KVM API (defined as 12) */
ret = KVM_IOCTL(kvm, KVM_GET_API_VERSION, NULL);
if (ret != 12)
errx(-EINVAL, "KVM_GET_API_VERSION %d, expected 12", ret);
return kvm;
}
int create_vm(int kvm, bool is_protected)
{
unsigned long flags = 0;
if (is_protected)
flags |= 1ul << 31;
return KVM_IOCTL(kvm, KVM_CREATE_VM, flags);
}
int create_vcpu(int kvm, int vmfd, struct kvm_run **run, bool enable_debug)
{
struct kvm_guest_debug debug = {
.control = KVM_GUESTDBG_ENABLE,
};
struct kvm_vcpu_init vcpu_init;
size_t mmap_size;
int vcpufd;
/* Create one CPU to run in the VM. */
vcpufd = KVM_IOCTL(vmfd, KVM_CREATE_VCPU, (unsigned long)0);
/* Map the shared kvm_run structure and following data. */
mmap_size = KVM_IOCTL(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
if (mmap_size < sizeof(*run))
err(-ENOMEM, "KVM_GET_VCPU_MMAP_SIZE unexpectedly small");
*run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);
if (!*run)
err(-ENOMEM, "mmap vcpu");
/* Query KVM for preferred CPU target type that can be emulated. */
KVM_IOCTL(vmfd, KVM_ARM_PREFERRED_TARGET, &vcpu_init);
KVM_IOCTL(vcpufd, KVM_ARM_VCPU_INIT, &vcpu_init);
if (enable_debug)
KVM_IOCTL(vcpufd, KVM_SET_GUEST_DEBUG, &debug);
return vcpufd;
}
void vm_add_mem_page(int vmfd, int slot, uint64_t addr, void *uaddr)
{
struct kvm_userspace_memory_region region = {
.slot = slot,
.guest_phys_addr = addr,
.userspace_addr = (uint64_t)uaddr,
.memory_size = PAGE_SIZE,
};
KVM_IOCTL(vmfd, KVM_SET_USER_MEMORY_REGION, &region);
}
void vm_add_mmio_page(int vmfd, int slot, uint64_t addr)
{
struct kvm_userspace_memory_region region = {
.flags = KVM_MEM_READONLY,
.slot = slot,
.guest_phys_addr = addr,
.userspace_addr = 0ULL,
.memory_size = PAGE_SIZE,
};
KVM_IOCTL(vmfd, KVM_SET_USER_MEMORY_REGION, &region);
}
void set_one_reg(int vcpufd, uint64_t reg_id, uint64_t val)
{
uint64_t reg_data;
struct kvm_one_reg reg;
reg.addr = (__u64) &reg_data;
reg_data = val;
reg.id = reg_id;
KVM_IOCTL(vcpufd, KVM_SET_ONE_REG, &reg);
}
/*
* Local variables:
* mode: C
* c-file-style: "Linux"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/