main.c 2.9 KB

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