qemu.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kvm.h>
#include <sys/mman.h>
#include <unistd.h>
int main()
{
struct kvm_sregs sregs;
int ret;
int kvmfd = open("/dev/kvm", O_RDWR);
ioctl(kvmfd, KVM_GET_API_VERSION, NULL);
int vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
unsigned char *ram = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
int kfd = open("./test.bin", O_RDONLY);
read(kfd, ram, 4096);
struct kvm_userspace_memory_region mem = {
.slot = 0,
.guest_phys_addr = 0,
.memory_size = 0x1000,
.userspace_addr = (unsigned long)ram,
};
ret = ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &mem);
int vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
int mmap_size = ioctl(kvmfd, KVM_GET_VCPU_MMAP_SIZE, NULL);
struct kvm_run *run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);
ret = ioctl(vcpufd, KVM_GET_SREGS, &sregs);
sregs.cs.base = 0;
sregs.cs.selector = 0;
ret = ioctl(vcpufd, KVM_SET_SREGS, &sregs);
struct kvm_regs regs = {
.rip = 0,
};
ret = ioctl(vcpufd, KVM_SET_REGS, ®s); //Notice: REGS, not SREGS.
while(1)
{
sleep(1);
ret = ioctl(vcpufd, KVM_RUN, NULL);
if (ret == -1)
{
printf("exit unknown\n");
return -1;
}
switch (run->exit_reason)
{
case KVM_EXIT_HLT:
puts("KVM_EXIT_HLT");
return 0;
case KVM_EXIT_IO:
putchar(*(((char *)run) + run->io.data_offset));
break;
case KVM_EXIT_FAIL_ENTRY:
puts("entry error");
return -1;
default:
puts("other error");
printf("exit_reason: %d\n", run->exit_reason);
return -1;
}
}
}
test.S
start:
mov $0x48,%al
outb %al,$0xf1
mov $0x65,%al
outb %al,$0xf1
mov $0x6c,%al
outb %al,$0xf1
mov $0x6c,%al
outb %al,$0xf1
mov $0x6f,%al
outb %al,$0xf1
mov $0x0a,%al
outb %al,$0xf1
hlt
Makefile
all:
as -32 test.S -o test.o
objcopy -O binary test.o test.bin
gcc qemu.c -o light-qemu
./light-qemu
output:
./light-qemu
Hello
KVM_EXIT_HLT