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