#include #include #include #include #include #include #include #include #include #include #include #include #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; } } }