xref: /DragonOS/user/apps/test_kvm/main.c (revision 1603395155fc166de0ac5f80369526e196526ed2)
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, &region);
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, &regs); // set registers
108 
109     ioctl(vcpufd, KVM_RUN, 0);
110 
111     return 0;
112 }
113 
114 
115