1 /** 2 * @file main.c 3 * @author xiaoyez (xiaoyez@zju.edu.cn) 4 * @brief 测试kvm的程序 5 * @version 0.1 6 * @date 2023-07-13 7 * 8 * @copyright Copyright (c) 2023 9 * 10 */ 11 12 /** 13 * 测试kvm命令的方法: 14 * 1.在DragonOS的控制台输入 exec bin/test_kvm.elf 15 * 16 */ 17 #include <fcntl.h> 18 #include <stdint.h> 19 #include <stdio.h> 20 #include <sys/ioctl.h> 21 #include <unistd.h> 22 23 #define KVM_CREATE_VCPU 0x00 24 #define KVM_SET_USER_MEMORY_REGION 0x01 25 26 #define KVM_RUN 0x00 27 #define KVM_GET_REGS 0x01 28 #define KVM_SET_REGS 0x02 29 30 struct kvm_userspace_memory_region { 31 uint32_t slot; // 要在哪个slot上注册内存区间 32 // flags有两个取值,KVM_MEM_LOG_DIRTY_PAGES和KVM_MEM_READONLY,用来指示kvm针对这段内存应该做的事情。 33 // KVM_MEM_LOG_DIRTY_PAGES用来开启内存脏页,KVM_MEM_READONLY用来开启内存只读。 34 uint32_t flags; 35 uint64_t guest_phys_addr; // 虚机内存区间起始物理地址 36 uint64_t memory_size; // 虚机内存区间大小 37 uint64_t userspace_addr; // 虚机内存区间对应的主机虚拟地址 38 }; 39 40 struct kvm_regs { 41 /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ 42 uint64_t rax, rbx, rcx, rdx; 43 uint64_t rsi, rdi, rsp, rbp; 44 uint64_t r8, r9, r10, r11; 45 uint64_t r12, r13, r14, r15; 46 uint64_t rip, rflags; 47 }; 48 49 int guest_code(){ 50 while (1) 51 { 52 // printf("guest code\n"); 53 __asm__ __volatile__ ( 54 "mov %rax, 0\n\t" 55 "mov %rcx, 0\n\t" 56 "cpuid\n\t" 57 ); 58 } 59 return 0; 60 } 61 62 int main() 63 { 64 printf("Test kvm running...\n"); 65 printf("Open /dev/kvm\n"); 66 int kvm_fd = open("/dev/kvm", O_RDWR|O_CLOEXEC); 67 int vmfd = ioctl(kvm_fd, 0x01, 0); 68 printf("vmfd=%d\n", vmfd); 69 70 /* 71 __asm__ __volatile__ ( 72 "mov %rax, 0\n\t" 73 "mov %rcx, 0\n\t" 74 "cpuid\n\t" 75 ); 76 */ 77 const uint8_t code[] = { 78 0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */ 79 0x00, 0xd8, /* add %bl, %al */ 80 0x04, '0', /* add $'0', %al */ 81 0xee, /* out %al, (%dx) */ 82 0xb0, '\n', /* mov $'\n', %al */ 83 0xee, /* out %al, (%dx) */ 84 0xf4, /* hlt */ 85 }; 86 87 size_t mem_size = 0x4000; // size of user memory you want to assign 88 printf("code=%p\n", code); 89 // void *mem = mmap(0, mem_size, 0x7, -1, 0); 90 // memcpy(mem, code, sizeof(code)); 91 struct kvm_userspace_memory_region region = { 92 .slot = 0, 93 .flags = 0, 94 .guest_phys_addr = 0, 95 .memory_size = mem_size, 96 .userspace_addr = (size_t)code 97 }; 98 ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, ®ion); 99 100 int vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0); 101 printf("vcpufd=%d\n", vcpufd); 102 int user_entry = 0x0; 103 104 struct kvm_regs regs = {0}; 105 regs.rip = user_entry; 106 regs.rsp = 0x3000; // stack address 107 regs.rflags = 0x2; // in x86 the 0x2 bit should always be set 108 ioctl(vcpufd, KVM_SET_REGS, ®s); // set registers 109 110 ioctl(vcpufd, KVM_RUN, 0); 111 112 return 0; 113 } 114 115 116