101 lines
2.4 KiB
C
101 lines
2.4 KiB
C
|
#include <linux/kvm.h>
|
||
|
#include <stdint.h>
|
||
|
#include <unistd.h>
|
||
|
#include <assert.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 <fcntl.h>
|
||
|
|
||
|
#define MSIZE 0x10000 // size of conventional memory
|
||
|
|
||
|
int main(int argc, char** argv) {
|
||
|
|
||
|
struct stat s;
|
||
|
int ret = stat(argv[1], &s);
|
||
|
if(ret) exit(!!printf("invalid file!\n"));
|
||
|
|
||
|
int kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
|
||
|
|
||
|
assert((ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY) ^ ioctl(kvm, KVM_GET_API_VERSION, NULL)) == 13);
|
||
|
|
||
|
int vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long)0),
|
||
|
vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0),
|
||
|
codefd = open(argv[1], O_RDONLY); // load boot sector from file
|
||
|
|
||
|
uint8_t* mem = mmap(NULL, MSIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); // allocate conventional memory for vm
|
||
|
|
||
|
mz* mzbuf = malloc(s.st_size);
|
||
|
read(codefd, mzbuf, s.st_size);
|
||
|
close(codefd);
|
||
|
|
||
|
mz_start ms;
|
||
|
uint32_t mzsz = loadmz(mzbuf, mem, 0x40, &ms);
|
||
|
|
||
|
struct kvm_userspace_memory_region memmap[2] = {
|
||
|
{
|
||
|
.guest_phys_addr = 0,
|
||
|
.memory_size = 0xA0000,
|
||
|
.userspace_addr = (uint64_t)mem,
|
||
|
},
|
||
|
/*{ // implied map
|
||
|
.guest_phys_addr = 0xA0000,
|
||
|
.memory_size = 0x20000,
|
||
|
.userspace_addr = (uint64_t)mem,
|
||
|
},*/
|
||
|
{
|
||
|
.guest_phys_addr = 0xC0000,
|
||
|
.memory_size = 0x40000,
|
||
|
.userspace_addr = (uint64_t)mem + 0xC0000,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
for(int i = 0; i < 2; i++) {
|
||
|
memmap[i].slot = i; // id of memory mapping
|
||
|
ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, memmap[i]);
|
||
|
}
|
||
|
|
||
|
struct kvm_sregs sregs;
|
||
|
struct kvm_run* run;
|
||
|
size_t run_size = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL); // size of struct is. determined at runtime for some reason?
|
||
|
run = mmap(NULL, run_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);
|
||
|
|
||
|
ioctl(vcpufd, KVM_GET_SREGS, &sregs);
|
||
|
|
||
|
sregs.cs.base = ms.cs;
|
||
|
sregs.ss.base = ms.ss;
|
||
|
|
||
|
sregs.cs.selector = 0; // probably protected mode related?
|
||
|
sregs.ss.selector = 0;
|
||
|
|
||
|
ioctl(vcpufd, KVM_SET_SREGS, &sregs);
|
||
|
|
||
|
struct kvm_regs regs = {
|
||
|
.rip = ms.ip,
|
||
|
.rsp = ms.sp,
|
||
|
.rflags = 0x2,
|
||
|
};
|
||
|
|
||
|
ioctl(vcpufd, KVM_SET_REGS, ®s);
|
||
|
|
||
|
while(1) {
|
||
|
ret = ioctl(vcpufd, KVM_RUN, NULL);
|
||
|
if(ret == -1) exit(!!printf("kvm error\n"));
|
||
|
switch (run->exit_reason) {
|
||
|
case KVM_EXIT_HLT:
|
||
|
exit(!printf("got instruction `hlt`, exiting\n"));
|
||
|
break;
|
||
|
case KVM_EXIT_IO:
|
||
|
|
||
|
break;
|
||
|
default:
|
||
|
exit(printf("vmexit\n"));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|