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
guest_code()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
main()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